Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(356)

Side by Side Diff: third_party/WebKit/Source/core/layout/GridTrackSizingAlgorithm.cpp

Issue 2654533003: [css-grid] Move the track sizing algorithm to its own class (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 #include "core/layout/GridTrackSizingAlgorithm.h"
2
3 #include "core/layout/Grid.h"
4 #include "core/layout/LayoutGrid.h"
5 #include "platform/LengthFunctions.h"
6
7 namespace blink {
8
9 class GridSizingData;
10
11 LayoutUnit GridTrack::baseSize() const {
12 DCHECK(isGrowthLimitBiggerThanBaseSize());
13 return m_baseSize;
14 }
15
16 LayoutUnit GridTrack::growthLimit() const {
17 DCHECK(isGrowthLimitBiggerThanBaseSize());
18 DCHECK(!m_growthLimitCap || m_growthLimitCap.value() >= m_growthLimit ||
19 m_baseSize >= m_growthLimitCap.value());
20 return m_growthLimit;
21 }
22
23 void GridTrack::setBaseSize(LayoutUnit baseSize) {
24 m_baseSize = baseSize;
25 ensureGrowthLimitIsBiggerThanBaseSize();
26 }
27
28 void GridTrack::setGrowthLimit(LayoutUnit growthLimit) {
29 m_growthLimit =
30 growthLimit == infinity
31 ? growthLimit
32 : std::min(growthLimit, m_growthLimitCap.value_or(growthLimit));
33 ensureGrowthLimitIsBiggerThanBaseSize();
34 }
35
36 void GridTrack::setPlannedSize(const LayoutUnit& plannedSize) {
37 DCHECK(plannedSize >= 0 || plannedSize == infinity);
38 m_plannedSize = plannedSize;
39 }
40
41 void GridTrack::setSizeDuringDistribution(
42 const LayoutUnit& sizeDuringDistribution) {
43 DCHECK_GE(sizeDuringDistribution, 0);
44 DCHECK(growthLimitIsInfinite() || growthLimit() >= sizeDuringDistribution);
45 m_sizeDuringDistribution = sizeDuringDistribution;
46 }
47
48 void GridTrack::growSizeDuringDistribution(
49 const LayoutUnit& sizeDuringDistribution) {
50 DCHECK_GE(sizeDuringDistribution, 0);
51 m_sizeDuringDistribution += sizeDuringDistribution;
52 }
53
54 void GridTrack::setGrowthLimitCap(Optional<LayoutUnit> growthLimitCap) {
55 DCHECK(!growthLimitCap || *growthLimitCap >= 0);
56 m_growthLimitCap = growthLimitCap;
57 }
58
59 bool GridTrack::isGrowthLimitBiggerThanBaseSize() const {
60 return growthLimitIsInfinite() || m_growthLimit >= m_baseSize;
Manuel Rego 2017/01/30 11:00:45 Again oneliner method here and not in the header.
svillar 2017/01/30 11:28:29 Again it isn't a one liner with the new coding sty
61 }
62
63 void GridTrack::ensureGrowthLimitIsBiggerThanBaseSize() {
64 if (m_growthLimit != infinity && m_growthLimit < m_baseSize)
65 m_growthLimit = m_baseSize;
66 }
67
68 class IndefiniteSizeStrategy final : public GridTrackSizingAlgorithmStrategy {
69 public:
70 IndefiniteSizeStrategy(GridTrackSizingAlgorithm& algorithm)
71 : GridTrackSizingAlgorithmStrategy(algorithm) {}
72
73 private:
74 LayoutUnit minContentForChild(LayoutBox& child) override;
Manuel Rego 2017/01/30 11:00:45 Name of the argument not needed here, and in the n
svillar 2017/01/30 11:28:29 Acknowledged.
75 LayoutUnit maxContentForChild(LayoutBox& child) const override;
76 LayoutUnit minSizeForChild(LayoutBox& child) override;
77 void maximizeTracks(Vector<GridTrack>&, LayoutUnit& freeSpace) override;
78 double findUsedFlexFraction(Vector<size_t>& flexibleSizedTracksIndex,
79 GridTrackSizingDirection,
80 LayoutUnit freeSpace) const override;
81 bool recomputeUsedFlexFractionIfNeeded(
82 Vector<size_t>& flexibleSizedTracksIndex,
83 double& flexFraction,
84 Vector<LayoutUnit>& increments,
85 LayoutUnit& totalGrowth) const override;
86 };
87
88 class DefiniteSizeStrategy final : public GridTrackSizingAlgorithmStrategy {
89 public:
90 DefiniteSizeStrategy(GridTrackSizingAlgorithm& algorithm)
91 : GridTrackSizingAlgorithmStrategy(algorithm) {}
92
93 private:
94 LayoutUnit minContentForChild(LayoutBox& child) override;
95 LayoutUnit maxContentForChild(LayoutBox& child) const override;
96 LayoutUnit minSizeForChild(LayoutBox& child) override;
97 void maximizeTracks(Vector<GridTrack>&, LayoutUnit& freeSpace) override;
98 double findUsedFlexFraction(Vector<size_t>& flexibleSizedTracksIndex,
99 GridTrackSizingDirection,
100 LayoutUnit freeSpace) const override;
101 bool recomputeUsedFlexFractionIfNeeded(
102 Vector<size_t>& flexibleSizedTracksIndex,
103 double& flexFraction,
104 Vector<LayoutUnit>& increments,
105 LayoutUnit& totalGrowth) const override {
106 return false;
107 }
108 };
109
110 // FIXME(ALGO): repeated in LayoutGrid
Manuel Rego 2017/01/30 11:00:45 What's this comment? It should be something like "
111 static LayoutUnit computeMarginLogicalSizeForChild(MarginDirection forDirection,
112 const LayoutGrid* grid,
113 const LayoutBox& child) {
114 if (!child.styleRef().hasMargin())
115 return LayoutUnit();
116
117 bool isRowAxis = forDirection == InlineDirection;
118 LayoutUnit marginStart;
119 LayoutUnit marginEnd;
120 LayoutUnit logicalSize =
121 isRowAxis ? child.logicalWidth() : child.logicalHeight();
122 Length marginStartLength = isRowAxis ? child.styleRef().marginStart()
123 : child.styleRef().marginBefore();
124 Length marginEndLength =
125 isRowAxis ? child.styleRef().marginEnd() : child.styleRef().marginAfter();
126 child.computeMarginsForDirection(
127 forDirection, grid, child.containingBlockLogicalWidthForContent(),
128 logicalSize, marginStart, marginEnd, marginStartLength, marginEndLength);
129
130 return marginStart + marginEnd;
131 }
132
133 static bool hasOverrideContainingBlockContentSizeForChild(
134 const LayoutBox& child,
135 GridTrackSizingDirection direction) {
136 return direction == ForColumns
137 ? child.hasOverrideContainingBlockLogicalWidth()
138 : child.hasOverrideContainingBlockLogicalHeight();
139 }
140
141 static LayoutUnit overrideContainingBlockContentSizeForChild(
142 const LayoutBox& child,
143 GridTrackSizingDirection direction) {
144 return direction == ForColumns
145 ? child.overrideContainingBlockContentLogicalWidth()
146 : child.overrideContainingBlockContentLogicalHeight();
147 }
148
149 static bool shouldClearOverrideContainingBlockContentSizeForChild(
150 const LayoutBox& child,
151 GridTrackSizingDirection direction) {
152 if (direction == ForColumns) {
153 return child.hasRelativeLogicalWidth() ||
154 child.styleRef().logicalWidth().isIntrinsicOrAuto();
155 }
156 return child.hasRelativeLogicalHeight() ||
157 child.styleRef().logicalHeight().isIntrinsicOrAuto();
158 }
159
160 static void setOverrideContainingBlockContentSizeForChild(
161 LayoutBox& child,
162 GridTrackSizingDirection direction,
163 LayoutUnit size) {
164 if (direction == ForColumns)
165 child.setOverrideContainingBlockContentLogicalWidth(size);
166 else
167 child.setOverrideContainingBlockContentLogicalHeight(size);
168 }
169
170 static GridTrackSizingDirection flowAwareDirectionForChild(
171 const LayoutGrid* layoutGrid,
172 const LayoutBox& child,
173 GridTrackSizingDirection direction) {
174 return child.isHorizontalWritingMode() ==
175 layoutGrid->isHorizontalWritingMode()
176 ? direction
177 : (direction == ForColumns ? ForRows : ForColumns);
178 }
179
180 LayoutUnit GridTrackSizingAlgorithm::assumedRowsSizeForOrthogonalChild(
181 const LayoutBox& child) const {
182 // DCHECK(isOrthogonalChild(child));
Manuel Rego 2017/01/30 11:00:45 Why is this commented out here? Shouldn't we need
183 const GridSpan& span = m_grid.gridItemSpan(child, ForRows);
184 LayoutUnit gridAreaSize;
185 bool gridAreaIsIndefinite = false;
186 LayoutUnit containingBlockAvailableSize =
187 m_layoutGrid->containingBlockLogicalHeightForContent(
188 ExcludeMarginBorderPadding);
189 for (auto trackPosition : span) {
190 GridLength maxTrackSize =
191 gridTrackSize(ForRows, trackPosition).maxTrackBreadth();
192 if (maxTrackSize.isContentSized() || maxTrackSize.isFlex()) {
193 gridAreaIsIndefinite = true;
194 } else {
195 gridAreaSize +=
196 valueForLength(maxTrackSize.length(), containingBlockAvailableSize);
197 }
198 }
199
200 gridAreaSize += m_layoutGrid->guttersSize(
201 m_grid, ForRows, span.startLine(), span.integerSpan(), m_sizingOperation);
202
203 return gridAreaIsIndefinite
204 ? std::max(child.maxPreferredLogicalWidth(), gridAreaSize)
205 : gridAreaSize;
206 }
207
208 LayoutUnit GridTrackSizingAlgorithm::gridAreaBreadthForChild(
209 const LayoutBox& child,
210 GridTrackSizingDirection direction) {
211 if (direction == ForRows && m_sizingState == ColumnSizingFirstIteration)
212 return assumedRowsSizeForOrthogonalChild(child);
213
214 Vector<GridTrack>& allTracks = tracks(direction);
215 const GridSpan& span = m_grid.gridItemSpan(child, direction);
216 LayoutUnit gridAreaBreadth;
217 for (const auto& trackPosition : span)
218 gridAreaBreadth += allTracks[trackPosition].baseSize();
219
220 gridAreaBreadth +=
221 m_layoutGrid->guttersSize(m_grid, direction, span.startLine(),
222 span.integerSpan(), m_sizingOperation);
223
224 return gridAreaBreadth;
225 }
226
227 bool GridTrackSizingAlgorithmStrategy::
228 updateOverrideContainingBlockContentSizeForChild(
229 LayoutBox& child,
230 GridTrackSizingDirection direction) const {
231 LayoutUnit overrideSize =
232 m_algorithm.gridAreaBreadthForChild(child, direction);
233 if (hasOverrideContainingBlockContentSizeForChild(child, direction) &&
234 overrideContainingBlockContentSizeForChild(child, direction) ==
235 overrideSize)
236 return false;
237
238 setOverrideContainingBlockContentSizeForChild(child, direction, overrideSize);
239 return true;
240 }
241
242 LayoutUnit GridTrackSizingAlgorithmStrategy::logicalHeightForChild(
243 LayoutBox& child) const {
244 GridTrackSizingDirection childBlockDirection =
245 flowAwareDirectionForChild(layoutGrid(), child, ForRows);
246
247 // If |child| has a relative logical height, we shouldn't let it override its
248 // intrinsic height, which is what we are interested in here. Thus we need to
249 // set the block-axis override size to -1 (no possible resolution).
250 if (shouldClearOverrideContainingBlockContentSizeForChild(child, ForRows)) {
251 setOverrideContainingBlockContentSizeForChild(child, childBlockDirection,
252 LayoutUnit(-1));
253 child.setNeedsLayout(LayoutInvalidationReason::GridChanged);
254 }
255
256 // We need to clear the stretched height to properly compute logical height
257 // during layout.
258 if (child.needsLayout())
259 child.clearOverrideLogicalContentHeight();
260
261 child.layoutIfNeeded();
262 return child.logicalHeight() + child.marginLogicalHeight();
263 }
264
265 DISABLE_CFI_PERF
266 LayoutUnit DefiniteSizeStrategy::minContentForChild(LayoutBox& child) {
Manuel Rego 2017/01/30 11:00:45 Wow this DefiniteSizeStrategy::minContentForChild
svillar 2017/01/30 11:28:29 Yes they're pretty similar, we could refactor part
267 GridTrackSizingDirection childInlineDirection =
268 flowAwareDirectionForChild(layoutGrid(), child, ForColumns);
269 if (direction() == childInlineDirection) {
270 // If |child| has a relative logical width, we shouldn't let it override its
271 // intrinsic width, which is what we are interested in here. Thus we need to
272 // set the inline-axis override size to -1 (no possible resolution).
273 if (shouldClearOverrideContainingBlockContentSizeForChild(child,
274 ForColumns)) {
275 setOverrideContainingBlockContentSizeForChild(child, childInlineDirection,
276 LayoutUnit(-1));
277 }
278
279 LayoutUnit marginLogicalWidth =
280 child.needsLayout() ? computeMarginLogicalSizeForChild(
281 InlineDirection, layoutGrid(), child)
282 : child.marginLogicalWidth();
283 return child.minPreferredLogicalWidth() + marginLogicalWidth;
284 }
285
286 if (updateOverrideContainingBlockContentSizeForChild(child,
287 childInlineDirection))
288 child.setNeedsLayout(LayoutInvalidationReason::GridChanged);
289 return logicalHeightForChild(child);
290 }
291
292 DISABLE_CFI_PERF
293 LayoutUnit DefiniteSizeStrategy::maxContentForChild(LayoutBox& child) const {
294 GridTrackSizingDirection childInlineDirection =
295 flowAwareDirectionForChild(layoutGrid(), child, ForColumns);
296 if (direction() == childInlineDirection) {
297 // If |child| has a relative logical width, we shouldn't let it override its
298 // intrinsic width, which is what we are interested in here. Thus we need to
299 // set the inline-axis override size to -1 (no possible resolution).
300 if (shouldClearOverrideContainingBlockContentSizeForChild(child,
301 ForColumns)) {
302 setOverrideContainingBlockContentSizeForChild(child, childInlineDirection,
303 LayoutUnit(-1));
304 }
305
306 // FIXME: It's unclear if we should return the intrinsic width or the
307 // preferred width.
308 // See http://lists.w3.org/Archives/Public/www-style/2013Jan/0245.html
309 LayoutUnit marginLogicalWidth =
310 child.needsLayout() ? computeMarginLogicalSizeForChild(
311 InlineDirection, layoutGrid(), child)
312 : child.marginLogicalWidth();
313 return child.maxPreferredLogicalWidth() + marginLogicalWidth;
314 }
315
316 if (updateOverrideContainingBlockContentSizeForChild(child,
317 childInlineDirection))
318 child.setNeedsLayout(LayoutInvalidationReason::GridChanged);
319 return logicalHeightForChild(child);
320 }
321
322 LayoutUnit DefiniteSizeStrategy::minSizeForChild(LayoutBox& child) {
323 GridTrackSizingDirection childInlineDirection =
324 flowAwareDirectionForChild(layoutGrid(), child, ForColumns);
325 bool isRowAxis = direction() == childInlineDirection;
326 const Length& childSize = isRowAxis ? child.styleRef().logicalWidth()
327 : child.styleRef().logicalHeight();
328 const Length& childMinSize = isRowAxis ? child.styleRef().logicalMinWidth()
329 : child.styleRef().logicalMinHeight();
330 bool overflowIsVisible =
331 isRowAxis
332 ? child.styleRef().overflowInlineDirection() == EOverflow::Visible
333 : child.styleRef().overflowBlockDirection() == EOverflow::Visible;
334 if (!childSize.isAuto() || (childMinSize.isAuto() && overflowIsVisible))
335 return minContentForChild(child);
336
337 bool overrideSizeHasChanged =
338 updateOverrideContainingBlockContentSizeForChild(child,
339 childInlineDirection);
340 if (isRowAxis) {
341 LayoutUnit marginLogicalWidth =
342 computeMarginLogicalSizeForChild(InlineDirection, layoutGrid(), child);
343 return child.computeLogicalWidthUsing(
344 MinSize, childMinSize,
345 overrideContainingBlockContentSizeForChild(child,
346 childInlineDirection),
347 layoutGrid()) +
348 marginLogicalWidth;
349 }
350
351 if (overrideSizeHasChanged)
352 child.setNeedsLayout(LayoutInvalidationReason::GridChanged);
353 child.layoutIfNeeded();
354 return child.computeLogicalHeightUsing(MinSize, childMinSize,
355 child.intrinsicLogicalHeight()) +
356 child.marginLogicalHeight() + child.scrollbarLogicalHeight();
357 }
358
359 void DefiniteSizeStrategy::maximizeTracks(Vector<GridTrack>& tracks,
360 LayoutUnit& freeSpace) {
361 size_t tracksSize = tracks.size();
362 Vector<GridTrack*> tracksForDistribution(tracksSize);
363 for (size_t i = 0; i < tracksSize; ++i) {
364 tracksForDistribution[i] = tracks.data() + i;
365 tracksForDistribution[i]->setPlannedSize(
366 tracksForDistribution[i]->baseSize());
367 }
368
369 distributeSpaceToTracks(tracksForDistribution, freeSpace);
370
371 for (auto* track : tracksForDistribution)
372 track->setBaseSize(track->plannedSize());
373 }
374
375 double DefiniteSizeStrategy::findUsedFlexFraction(
376 Vector<size_t>& flexibleSizedTracksIndex,
377 GridTrackSizingDirection direction,
378 LayoutUnit freeSpace) const {
379 GridSpan allTracksSpan = GridSpan::translatedDefiniteGridSpan(
380 0, m_algorithm.tracks(direction).size());
381 return findFrUnitSize(allTracksSpan, freeSpace);
382 }
383
384 DISABLE_CFI_PERF
385 LayoutUnit IndefiniteSizeStrategy::minContentForChild(LayoutBox& child) {
386 GridTrackSizingDirection childInlineDirection =
387 flowAwareDirectionForChild(layoutGrid(), child, ForColumns);
388 if (direction() == childInlineDirection) {
389 // If |child| has a relative logical width, we shouldn't let it override its
390 // intrinsic width, which is what we are interested in here. Thus we need to
391 // set the inline-axis override size to -1 (no possible resolution).
392 if (shouldClearOverrideContainingBlockContentSizeForChild(child,
393 ForColumns)) {
394 setOverrideContainingBlockContentSizeForChild(child, childInlineDirection,
395 LayoutUnit(-1));
396 }
397
398 // FIXME: It's unclear if we should return the intrinsic width or the
399 // preferred width.
400 // See http://lists.w3.org/Archives/Public/www-style/2013Jan/0245.html
401 LayoutUnit marginLogicalWidth =
402 child.needsLayout() ? computeMarginLogicalSizeForChild(
403 InlineDirection, layoutGrid(), child)
404 : child.marginLogicalWidth();
405 return child.minPreferredLogicalWidth() + marginLogicalWidth;
406 }
407
408 // All orthogonal flow boxes were already laid out during an early layout
409 // phase performed in FrameView::performLayout.
410 // It's true that grid track sizing was not completed at that time and it may
411 // afffect the final height of a grid item, but since it's forbidden to
412 // perform a layout during intrinsic width computation, we have to use that
413 // computed height for now.
414 if (direction() == ForColumns) {
415 // TODO(ALGO)
416 // DCHECK(isOrthogonalChild(child));
417 return child.logicalHeight() + child.marginLogicalHeight();
418 }
419
420 if (updateOverrideContainingBlockContentSizeForChild(child,
421 childInlineDirection))
422 child.setNeedsLayout(LayoutInvalidationReason::GridChanged);
423 return logicalHeightForChild(child);
424 }
425
426 DISABLE_CFI_PERF
427 LayoutUnit IndefiniteSizeStrategy::maxContentForChild(LayoutBox& child) const {
428 GridTrackSizingDirection childInlineDirection =
429 flowAwareDirectionForChild(layoutGrid(), child, ForColumns);
430 if (direction() == childInlineDirection) {
431 // If |child| has a relative logical width, we shouldn't let it override its
432 // intrinsic width, which is what we are interested in here. Thus we need to
433 // set the inline-axis override size to -1 (no possible resolution).
434 if (shouldClearOverrideContainingBlockContentSizeForChild(child,
435 ForColumns)) {
436 setOverrideContainingBlockContentSizeForChild(child, childInlineDirection,
437 LayoutUnit(-1));
438 }
439
440 // FIXME: It's unclear if we should return the intrinsic width or the
441 // preferred width.
442 // See http://lists.w3.org/Archives/Public/www-style/2013Jan/0245.html
443 LayoutUnit marginLogicalWidth =
444 child.needsLayout() ? computeMarginLogicalSizeForChild(
445 InlineDirection, layoutGrid(), child)
446 : child.marginLogicalWidth();
447 return child.maxPreferredLogicalWidth() + marginLogicalWidth;
448 }
449
450 // All orthogonal flow boxes were already laid out during an early layout
451 // phase performed in FrameView::performLayout.
452 // It's true that grid track sizing was not completed at that time and it may
453 // afffect the final height of a grid item, but since it's forbidden to
454 // perform a layout during intrinsic width computation, we have to use that
455 // computed height for now.
456 if (direction() == ForColumns) {
457 // TODO(ALGO)
Manuel Rego 2017/01/30 11:00:45 Again a weird TODO here.
458 // DCHECK(isOrthogonalChild(child));
459 return child.logicalHeight() + child.marginLogicalHeight();
460 }
461
462 if (updateOverrideContainingBlockContentSizeForChild(child,
463 childInlineDirection))
464 child.setNeedsLayout(LayoutInvalidationReason::GridChanged);
465 return logicalHeightForChild(child);
466 }
467
468 LayoutUnit IndefiniteSizeStrategy::minSizeForChild(LayoutBox& child) {
469 GridTrackSizingDirection childInlineDirection =
470 flowAwareDirectionForChild(layoutGrid(), child, ForColumns);
471 bool isRowAxis = direction() == childInlineDirection;
472 const Length& childSize = isRowAxis ? child.styleRef().logicalWidth()
473 : child.styleRef().logicalHeight();
474 const Length& childMinSize = isRowAxis ? child.styleRef().logicalMinWidth()
475 : child.styleRef().logicalMinHeight();
476 bool overflowIsVisible =
477 isRowAxis
478 ? child.styleRef().overflowInlineDirection() == EOverflow::Visible
479 : child.styleRef().overflowBlockDirection() == EOverflow::Visible;
480 if (!childSize.isAuto() || (childMinSize.isAuto() && overflowIsVisible))
481 return minContentForChild(child);
482
483 bool overrideSizeHasChanged =
484 updateOverrideContainingBlockContentSizeForChild(child,
485 childInlineDirection);
486 if (isRowAxis) {
487 // TODO(ALGO): marginIntrinsicLogicalWidthForChild is protected for
Manuel Rego 2017/01/30 11:00:45 You shouldn't use "ALGO", use "svillar" instead. A
svillar 2017/01/30 11:28:29 Yeah, I used those for tracking while refactoring
488 // LayoutObjects
489 LayoutUnit marginLogicalWidth = LayoutUnit();
490 // layoutGrid()->marginIntrinsicLogicalWidthForChild(child);
491 return child.computeLogicalWidthUsing(
492 MinSize, childMinSize,
493 overrideContainingBlockContentSizeForChild(child,
494 childInlineDirection),
495 layoutGrid()) +
496 marginLogicalWidth;
497 }
498
499 if (overrideSizeHasChanged && direction() != ForColumns)
500 child.setNeedsLayout(LayoutInvalidationReason::GridChanged);
501 child.layoutIfNeeded();
502 return child.computeLogicalHeightUsing(MinSize, childMinSize,
503 child.intrinsicLogicalHeight()) +
504 child.marginLogicalHeight() + child.scrollbarLogicalHeight();
505 }
506
507 void IndefiniteSizeStrategy::maximizeTracks(Vector<GridTrack>& tracks,
508 LayoutUnit&) {
509 for (auto& track : tracks)
510 track.setBaseSize(track.growthLimit());
511 }
512
513 static inline double normalizedFlexFraction(const GridTrack& track,
514 double flexFactor) {
515 return track.baseSize() / std::max<double>(1, flexFactor);
516 }
517
518 double IndefiniteSizeStrategy::findUsedFlexFraction(
519 Vector<size_t>& flexibleSizedTracksIndex,
520 GridTrackSizingDirection direction,
521 LayoutUnit freeSpace) const {
522 auto allTracks = m_algorithm.tracks(direction);
523
524 double flexFraction = 0;
525 for (const auto& trackIndex : flexibleSizedTracksIndex) {
526 // FIXME(svillar): we pass TrackSizing to gridTrackSize() because it does
527 // not really matter as we know
528 // the track is a flex sized track. It'd be nice not to have to do that.
529 flexFraction = std::max(
530 flexFraction,
531 normalizedFlexFraction(
532 allTracks[trackIndex],
533 m_algorithm.gridTrackSize(direction, trackIndex, TrackSizing)
534 .maxTrackBreadth()
535 .flex()));
536 }
537
538 const Grid& grid = m_algorithm.grid();
539 if (!grid.hasGridItems())
540 return flexFraction;
541
542 for (size_t i = 0; i < flexibleSizedTracksIndex.size(); ++i) {
543 GridIterator iterator(grid, direction, flexibleSizedTracksIndex[i]);
544 while (LayoutBox* gridItem = iterator.nextGridItem()) {
545 const GridSpan& span = grid.gridItemSpan(*gridItem, direction);
546
547 // Do not include already processed items.
548 if (i > 0 && span.startLine() <= flexibleSizedTracksIndex[i - 1])
549 continue;
550
551 flexFraction = std::max(
552 flexFraction, findFrUnitSize(span, maxContentForChild(*gridItem)));
553 }
554 }
555
556 return flexFraction;
557 }
558
559 bool IndefiniteSizeStrategy::recomputeUsedFlexFractionIfNeeded(
560 Vector<size_t>& flexibleSizedTracksIndex,
561 double& flexFraction,
562 Vector<LayoutUnit>& increments,
563 LayoutUnit& totalGrowth) const {
564 if (direction() == ForColumns)
565 return false;
566
567 const LayoutGrid* layoutGrid = this->layoutGrid();
568 LayoutUnit minSize = layoutGrid->computeContentLogicalHeight(
569 MinSize, layoutGrid->styleRef().logicalMinHeight(), LayoutUnit(-1));
570 LayoutUnit maxSize = layoutGrid->computeContentLogicalHeight(
571 MaxSize, layoutGrid->styleRef().logicalMaxHeight(), LayoutUnit(-1));
572
573 // Redo the flex fraction computation using min|max-height as definite
574 // available space in case the total height is smaller than min-height or
575 // larger than max-height.
576 LayoutUnit rowsSize = totalGrowth + computeTrackBasedSize();
577 bool checkMinSize = minSize && rowsSize < minSize;
578 bool checkMaxSize = maxSize != -1 && rowsSize > maxSize;
579 if (!checkMinSize && !checkMaxSize)
580 return false;
581
582 LayoutUnit freeSpace = checkMaxSize ? maxSize : LayoutUnit(-1);
583 const Grid& grid = m_algorithm.grid();
584 freeSpace = std::max(freeSpace, minSize) -
585 layoutGrid->guttersSize(grid, ForRows, 0, grid.numTracks(ForRows),
586 IntrinsicSizeComputation);
587
588 size_t numberOfTracks = m_algorithm.tracks(direction()).size();
589 flexFraction = findFrUnitSize(
590 GridSpan::translatedDefiniteGridSpan(0, numberOfTracks), freeSpace);
591 return true;
592 }
593
594 // The GridTrackSizingAlgorithm
595 //
596 Vector<GridTrack>& GridTrackSizingAlgorithm::tracks(
597 GridTrackSizingDirection direction) {
598 return direction == ForColumns ? m_columns : m_rows;
599 }
600
601 const Vector<GridTrack>& GridTrackSizingAlgorithm::tracks(
602 GridTrackSizingDirection direction) const {
603 return direction == ForColumns ? m_columns : m_rows;
604 }
605
606 void GridTrackSizingAlgorithm::setup(GridTrackSizingDirection direction,
607 size_t numTracks,
608 SizingOperation sizingOperation,
609 LayoutUnit availableSpace,
610 LayoutUnit freeSpace) {
611 DCHECK(m_needsSetup);
612 m_direction = direction;
613 m_availableSpace = availableSpace;
614
615 m_sizingOperation = sizingOperation;
616 switch (m_sizingOperation) {
617 case IntrinsicSizeComputation:
618 m_strategy = WTF::makeUnique<IndefiniteSizeStrategy>(*this);
619 break;
620 case TrackSizing:
621 m_strategy = WTF::makeUnique<DefiniteSizeStrategy>(*this);
622 break;
623 }
624
625 m_contentSizedTracksIndex.shrink(0);
626 m_flexibleSizedTracksIndex.shrink(0);
627
628 this->freeSpace(direction) = freeSpace;
629 tracks(direction).resize(numTracks);
630
631 m_needsSetup = false;
632 }
633
634 GridTrackSize GridTrackSizingAlgorithm::rawGridTrackSize(
635 GridTrackSizingDirection direction,
636 size_t translatedIndex) const {
637 bool isRowAxis = direction == ForColumns;
638 const Vector<GridTrackSize>& trackStyles =
639 isRowAxis ? m_layoutGrid->styleRef().gridTemplateColumns()
640 : m_layoutGrid->styleRef().gridTemplateRows();
641 const Vector<GridTrackSize>& autoRepeatTrackStyles =
642 isRowAxis ? m_layoutGrid->styleRef().gridAutoRepeatColumns()
643 : m_layoutGrid->styleRef().gridAutoRepeatRows();
644 const Vector<GridTrackSize>& autoTrackStyles =
645 isRowAxis ? m_layoutGrid->styleRef().gridAutoColumns()
646 : m_layoutGrid->styleRef().gridAutoRows();
647 size_t insertionPoint =
648 isRowAxis ? m_layoutGrid->styleRef().gridAutoRepeatColumnsInsertionPoint()
649 : m_layoutGrid->styleRef().gridAutoRepeatRowsInsertionPoint();
650 size_t autoRepeatTracksCount = m_grid.autoRepeatTracks(direction);
651
652 // We should not use GridPositionsResolver::explicitGridXXXCount() for this
653 // because the explicit grid might be larger than the number of tracks in
654 // grid-template-rows|columns (if grid-template-areas is specified for
655 // example).
656 size_t explicitTracksCount = trackStyles.size() + autoRepeatTracksCount;
657
658 int untranslatedIndexAsInt =
659 translatedIndex + m_grid.smallestTrackStart(direction);
660 size_t autoTrackStylesSize = autoTrackStyles.size();
661 if (untranslatedIndexAsInt < 0) {
662 int index = untranslatedIndexAsInt % static_cast<int>(autoTrackStylesSize);
663 // We need to traspose the index because the first negative implicit line
664 // will get the last defined auto track and so on.
665 index += index ? autoTrackStylesSize : 0;
666 return autoTrackStyles[index];
667 }
668
669 size_t untranslatedIndex = static_cast<size_t>(untranslatedIndexAsInt);
670 if (untranslatedIndex >= explicitTracksCount) {
671 return autoTrackStyles[(untranslatedIndex - explicitTracksCount) %
672 autoTrackStylesSize];
673 }
674
675 if (LIKELY(!autoRepeatTracksCount) || untranslatedIndex < insertionPoint)
676 return trackStyles[untranslatedIndex];
677
678 if (untranslatedIndex < (insertionPoint + autoRepeatTracksCount)) {
679 size_t autoRepeatLocalIndex = untranslatedIndexAsInt - insertionPoint;
680 return autoRepeatTrackStyles[autoRepeatLocalIndex %
681 autoRepeatTrackStyles.size()];
682 }
683
684 return trackStyles[untranslatedIndex - autoRepeatTracksCount];
685 }
686
687 GridTrackSize GridTrackSizingAlgorithm::gridTrackSize(
688 GridTrackSizingDirection direction,
689 size_t translatedIndex) const {
690 return gridTrackSize(direction, translatedIndex, m_sizingOperation);
691 }
692
693 GridTrackSize GridTrackSizingAlgorithm::gridTrackSize(
694 GridTrackSizingDirection direction,
695 size_t translatedIndex,
696 SizingOperation sizingOperation) const {
697 // Collapse empty auto repeat tracks if auto-fit.
698 if (m_grid.hasAutoRepeatEmptyTracks(direction) &&
699 m_grid.isEmptyAutoRepeatTrack(direction, translatedIndex))
700 return {Length(Fixed), LengthTrackSizing};
701
702 const GridTrackSize& trackSize = rawGridTrackSize(direction, translatedIndex);
703 if (trackSize.isFitContent())
704 return trackSize;
705
706 GridLength minTrackBreadth = trackSize.minTrackBreadth();
707 GridLength maxTrackBreadth = trackSize.maxTrackBreadth();
708 // If the logical width/height of the grid container is indefinite, percentage
709 // values are treated as <auto>.
710 if (minTrackBreadth.hasPercentage() || maxTrackBreadth.hasPercentage()) {
711 // For the inline axis this only happens when we're computing the intrinsic
712 // sizes (AvailableSpaceIndefinite).
713 if ((sizingOperation == IntrinsicSizeComputation) ||
714 (direction == ForRows &&
715 !m_layoutGrid->cachedHasDefiniteLogicalHeight())) {
716 if (minTrackBreadth.hasPercentage())
717 minTrackBreadth = Length(Auto);
718 if (maxTrackBreadth.hasPercentage())
719 maxTrackBreadth = Length(Auto);
720 }
721 }
722
723 // Flex sizes are invalid as a min sizing function. However we still can have
724 // a flexible |minTrackBreadth| if the track had a flex size directly (e.g.
725 // "1fr"), the spec says that in this case it implies an automatic minimum.
726 if (minTrackBreadth.isFlex())
727 minTrackBreadth = Length(Auto);
728
729 return GridTrackSize(minTrackBreadth, maxTrackBreadth);
730 }
731
732 LayoutUnit GridTrackSizingAlgorithm::initialBaseSize(
733 const GridTrackSize& trackSize) const {
734 const GridLength& gridLength = trackSize.minTrackBreadth();
735 if (gridLength.isFlex())
736 return LayoutUnit();
737
738 const Length& trackLength = gridLength.length();
739 if (trackLength.isSpecified())
740 return valueForLength(trackLength, m_availableSpace.clampNegativeToZero());
741
742 DCHECK(trackLength.isMinContent() || trackLength.isAuto() ||
743 trackLength.isMaxContent());
744 return LayoutUnit();
745 }
746
747 LayoutUnit GridTrackSizingAlgorithm::initialGrowthLimit(
748 const GridTrackSize& trackSize,
749 LayoutUnit baseSize) const {
750 const GridLength& gridLength = trackSize.maxTrackBreadth();
751 if (gridLength.isFlex())
752 return baseSize;
753
754 const Length& trackLength = gridLength.length();
755 if (trackLength.isSpecified())
756 return valueForLength(trackLength, m_availableSpace.clampNegativeToZero());
757
758 DCHECK(trackLength.isMinContent() || trackLength.isAuto() ||
759 trackLength.isMaxContent());
760 return LayoutUnit(infinity);
761 }
762
763 void GridTrackSizingAlgorithm::initializeTrackSizes() {
764 DCHECK(m_contentSizedTracksIndex.isEmpty());
765 DCHECK(m_flexibleSizedTracksIndex.isEmpty());
766 Vector<GridTrack>& trackList = tracks(m_direction);
767 bool hasDefiniteFreeSpace = m_sizingOperation == TrackSizing;
768 size_t numTracks = trackList.size();
769 for (size_t i = 0; i < numTracks; ++i) {
770 GridTrackSize trackSize = gridTrackSize(m_direction, i);
771 GridTrack& track = trackList[i];
772 track.setBaseSize(initialBaseSize(trackSize));
773 track.setGrowthLimit(initialGrowthLimit(trackSize, track.baseSize()));
774 track.setInfinitelyGrowable(false);
775
776 if (trackSize.isFitContent()) {
777 GridLength gridLength = trackSize.fitContentTrackBreadth();
778 if (!gridLength.hasPercentage() || hasDefiniteFreeSpace) {
779 track.setGrowthLimitCap(valueForLength(
780 gridLength.length(), m_availableSpace.clampNegativeToZero()));
781 }
782 }
783
784 if (trackSize.isContentSized())
785 m_contentSizedTracksIndex.append(i);
786 if (trackSize.maxTrackBreadth().isFlex())
787 m_flexibleSizedTracksIndex.append(i);
788 }
789 }
790
791 void GridTrackSizingAlgorithm::sizeTrackToFitNonSpanningItem(
792 const GridSpan& span,
793 LayoutBox& gridItem,
794 GridTrack& track) {
795 const size_t trackPosition = span.startLine();
796 GridTrackSize trackSize = gridTrackSize(m_direction, trackPosition);
797
798 if (trackSize.hasMinContentMinTrackBreadth()) {
799 track.setBaseSize(
800 std::max(track.baseSize(), m_strategy->minContentForChild(gridItem)));
801 } else if (trackSize.hasMaxContentMinTrackBreadth()) {
802 track.setBaseSize(
803 std::max(track.baseSize(), m_strategy->maxContentForChild(gridItem)));
804 } else if (trackSize.hasAutoMinTrackBreadth()) {
805 track.setBaseSize(
806 std::max(track.baseSize(), m_strategy->minSizeForChild(gridItem)));
807 }
808
809 if (trackSize.hasMinContentMaxTrackBreadth()) {
810 track.setGrowthLimit(std::max(track.growthLimit(),
811 m_strategy->minContentForChild(gridItem)));
812 } else if (trackSize.hasMaxContentOrAutoMaxTrackBreadth()) {
813 LayoutUnit growthLimit = m_strategy->maxContentForChild(gridItem);
814 if (trackSize.isFitContent()) {
815 growthLimit =
816 std::min(growthLimit,
817 valueForLength(trackSize.fitContentTrackBreadth().length(),
818 m_availableSpace));
819 }
820 track.setGrowthLimit(std::max(track.growthLimit(), growthLimit));
821 }
822 }
823
824 bool GridTrackSizingAlgorithm::spanningItemCrossesFlexibleSizedTracks(
825 const GridSpan& span) const {
826 for (const auto& trackPosition : span) {
827 const GridTrackSize& trackSize = gridTrackSize(m_direction, trackPosition);
828 if (trackSize.minTrackBreadth().isFlex() ||
829 trackSize.maxTrackBreadth().isFlex())
830 return true;
831 }
832
833 return false;
834 }
835
836 // We're basically using a class instead of a std::pair because of accessing
837 // gridItem() or getGridSpan() is much more self-explanatory that using .first
838 // or .second members in the pair. Having a std::pair<LayoutBox*, size_t>
839 // does not work either because we still need the GridSpan so we'd have to add
840 // an extra hash lookup for each item at the beginning of
841 // LayoutGrid::increaseSizesToAccommodateSpanningItems().
842 class GridItemWithSpan {
843 public:
844 GridItemWithSpan(LayoutBox& gridItem, const GridSpan& gridSpan)
845 : m_gridItem(&gridItem), m_gridSpan(gridSpan) {}
846
847 LayoutBox& gridItem() const { return *m_gridItem; }
848 GridSpan getGridSpan() const { return m_gridSpan; }
849
850 bool operator<(const GridItemWithSpan other) const {
851 return m_gridSpan.integerSpan() < other.m_gridSpan.integerSpan();
852 }
853
854 private:
855 LayoutBox* m_gridItem;
856 GridSpan m_gridSpan;
857 };
858
859 struct GridItemsSpanGroupRange {
860 Vector<GridItemWithSpan>::iterator rangeStart;
861 Vector<GridItemWithSpan>::iterator rangeEnd;
862 };
863
864 enum TrackSizeRestriction {
865 AllowInfinity,
866 ForbidInfinity,
867 };
868
869 static LayoutUnit trackSizeForTrackSizeComputationPhase(
870 TrackSizeComputationPhase phase,
871 const GridTrack& track,
872 TrackSizeRestriction restriction) {
873 switch (phase) {
874 case ResolveIntrinsicMinimums:
875 case ResolveContentBasedMinimums:
876 case ResolveMaxContentMinimums:
877 case MaximizeTracks:
878 return track.baseSize();
879 case ResolveIntrinsicMaximums:
880 case ResolveMaxContentMaximums:
881 const LayoutUnit& growthLimit = track.growthLimit();
882 if (restriction == AllowInfinity)
883 return growthLimit;
884 return growthLimit == infinity ? track.baseSize() : growthLimit;
885 }
886
887 NOTREACHED();
888 return track.baseSize();
889 }
890
891 static bool shouldProcessTrackForTrackSizeComputationPhase(
892 TrackSizeComputationPhase phase,
893 const GridTrackSize& trackSize) {
894 switch (phase) {
895 case ResolveIntrinsicMinimums:
896 return trackSize.hasIntrinsicMinTrackBreadth();
897 case ResolveContentBasedMinimums:
898 return trackSize.hasMinOrMaxContentMinTrackBreadth();
899 case ResolveMaxContentMinimums:
900 return trackSize.hasMaxContentMinTrackBreadth();
901 case ResolveIntrinsicMaximums:
902 return trackSize.hasIntrinsicMaxTrackBreadth();
903 case ResolveMaxContentMaximums:
904 return trackSize.hasMaxContentOrAutoMaxTrackBreadth();
905 case MaximizeTracks:
906 NOTREACHED();
907 return false;
908 }
909
910 NOTREACHED();
911 return false;
912 }
913
914 static bool trackShouldGrowBeyondGrowthLimitsForTrackSizeComputationPhase(
915 TrackSizeComputationPhase phase,
916 const GridTrackSize& trackSize) {
917 switch (phase) {
918 case ResolveIntrinsicMinimums:
919 case ResolveContentBasedMinimums:
920 return trackSize
921 .hasAutoOrMinContentMinTrackBreadthAndIntrinsicMaxTrackBreadth();
922 case ResolveMaxContentMinimums:
923 return trackSize
924 .hasMaxContentMinTrackBreadthAndMaxContentMaxTrackBreadth();
925 case ResolveIntrinsicMaximums:
926 case ResolveMaxContentMaximums:
927 return true;
928 case MaximizeTracks:
929 NOTREACHED();
930 return false;
931 }
932
933 NOTREACHED();
934 return false;
935 }
936
937 static void markAsInfinitelyGrowableForTrackSizeComputationPhase(
938 TrackSizeComputationPhase phase,
939 GridTrack& track) {
940 switch (phase) {
941 case ResolveIntrinsicMinimums:
942 case ResolveContentBasedMinimums:
943 case ResolveMaxContentMinimums:
944 return;
945 case ResolveIntrinsicMaximums:
946 if (trackSizeForTrackSizeComputationPhase(phase, track, AllowInfinity) ==
947 infinity &&
948 track.plannedSize() != infinity)
949 track.setInfinitelyGrowable(true);
950 return;
951 case ResolveMaxContentMaximums:
952 if (track.infinitelyGrowable())
953 track.setInfinitelyGrowable(false);
954 return;
955 case MaximizeTracks:
956 NOTREACHED();
957 return;
958 }
959
960 NOTREACHED();
961 }
962
963 static void updateTrackSizeForTrackSizeComputationPhase(
964 TrackSizeComputationPhase phase,
965 GridTrack& track) {
966 switch (phase) {
967 case ResolveIntrinsicMinimums:
968 case ResolveContentBasedMinimums:
969 case ResolveMaxContentMinimums:
970 track.setBaseSize(track.plannedSize());
971 return;
972 case ResolveIntrinsicMaximums:
973 case ResolveMaxContentMaximums:
974 track.setGrowthLimit(track.plannedSize());
975 return;
976 case MaximizeTracks:
977 NOTREACHED();
978 return;
979 }
980
981 NOTREACHED();
982 }
983
984 LayoutUnit GridTrackSizingAlgorithm::itemSizeForTrackSizeComputationPhase(
985 TrackSizeComputationPhase phase,
986 LayoutBox& gridItem) const {
987 switch (phase) {
988 case ResolveIntrinsicMinimums:
989 case ResolveIntrinsicMaximums:
990 return m_strategy->minSizeForChild(gridItem);
991 case ResolveContentBasedMinimums:
992 return m_strategy->minContentForChild(gridItem);
993 case ResolveMaxContentMinimums:
994 case ResolveMaxContentMaximums:
995 return m_strategy->maxContentForChild(gridItem);
996 case MaximizeTracks:
997 NOTREACHED();
998 return LayoutUnit();
999 }
1000
1001 NOTREACHED();
1002 return LayoutUnit();
1003 }
1004
1005 static bool sortByGridTrackGrowthPotential(const GridTrack* track1,
1006 const GridTrack* track2) {
1007 // This check ensures that we respect the irreflexivity property of the strict
1008 // weak ordering required by std::sort(forall x: NOT x < x).
1009 bool track1HasInfiniteGrowthPotentialWithoutCap =
1010 track1->infiniteGrowthPotential() && !track1->growthLimitCap();
1011 bool track2HasInfiniteGrowthPotentialWithoutCap =
1012 track2->infiniteGrowthPotential() && !track2->growthLimitCap();
1013
1014 if (track1HasInfiniteGrowthPotentialWithoutCap &&
1015 track2HasInfiniteGrowthPotentialWithoutCap)
1016 return false;
1017
1018 if (track1HasInfiniteGrowthPotentialWithoutCap ||
1019 track2HasInfiniteGrowthPotentialWithoutCap)
1020 return track2HasInfiniteGrowthPotentialWithoutCap;
1021
1022 LayoutUnit track1Limit =
1023 track1->growthLimitCap().value_or(track1->growthLimit());
1024 LayoutUnit track2Limit =
1025 track2->growthLimitCap().value_or(track2->growthLimit());
1026 return (track1Limit - track1->baseSize()) <
1027 (track2Limit - track2->baseSize());
1028 }
1029
1030 static void clampGrowthShareIfNeeded(TrackSizeComputationPhase phase,
1031 const GridTrack& track,
1032 LayoutUnit& growthShare) {
1033 if (phase != ResolveMaxContentMaximums || !track.growthLimitCap())
1034 return;
1035
1036 LayoutUnit distanceToCap =
1037 track.growthLimitCap().value() - track.sizeDuringDistribution();
1038 if (distanceToCap <= 0)
1039 return;
1040
1041 growthShare = std::min(growthShare, distanceToCap);
1042 }
1043
1044 template <TrackSizeComputationPhase phase>
1045 void GridTrackSizingAlgorithm::distributeSpaceToTracks(
1046 Vector<GridTrack*>& tracks,
1047 Vector<GridTrack*>* growBeyondGrowthLimitsTracks,
1048 LayoutUnit& availableLogicalSpace) const {
1049 DCHECK_GE(availableLogicalSpace, 0);
1050
1051 for (auto* track : tracks) {
1052 track->setSizeDuringDistribution(
1053 trackSizeForTrackSizeComputationPhase(phase, *track, ForbidInfinity));
1054 }
1055
1056 if (availableLogicalSpace > 0) {
1057 std::sort(tracks.begin(), tracks.end(), sortByGridTrackGrowthPotential);
1058
1059 size_t tracksSize = tracks.size();
1060 for (size_t i = 0; i < tracksSize; ++i) {
1061 GridTrack& track = *tracks[i];
1062 LayoutUnit availableLogicalSpaceShare =
1063 availableLogicalSpace / (tracksSize - i);
1064 const LayoutUnit& trackBreadth =
1065 trackSizeForTrackSizeComputationPhase(phase, track, ForbidInfinity);
1066 LayoutUnit growthShare =
1067 track.infiniteGrowthPotential()
1068 ? availableLogicalSpaceShare
1069 : std::min(availableLogicalSpaceShare,
1070 track.growthLimit() - trackBreadth);
1071 clampGrowthShareIfNeeded(phase, track, growthShare);
1072 DCHECK_GE(growthShare, 0) << "We must never shrink any grid track or "
1073 "else we can't guarantee we abide by our "
1074 "min-sizing function.";
1075 track.growSizeDuringDistribution(growthShare);
1076 availableLogicalSpace -= growthShare;
1077 }
1078 }
1079
1080 if (availableLogicalSpace > 0 && growBeyondGrowthLimitsTracks) {
1081 // We need to sort them because there might be tracks with growth limit caps
1082 // (like the ones with fit-content()) which cannot indefinitely grow over
1083 // the limits.
1084 if (phase == ResolveMaxContentMaximums) {
1085 std::sort(growBeyondGrowthLimitsTracks->begin(),
1086 growBeyondGrowthLimitsTracks->end(),
1087 sortByGridTrackGrowthPotential);
1088 }
1089
1090 size_t tracksGrowingAboveMaxBreadthSize =
1091 growBeyondGrowthLimitsTracks->size();
1092 for (size_t i = 0; i < tracksGrowingAboveMaxBreadthSize; ++i) {
1093 GridTrack* track = growBeyondGrowthLimitsTracks->at(i);
1094 LayoutUnit growthShare =
1095 availableLogicalSpace / (tracksGrowingAboveMaxBreadthSize - i);
1096 clampGrowthShareIfNeeded(phase, *track, growthShare);
1097 DCHECK_GE(growthShare, 0) << "We must never shrink any grid track or "
1098 "else we can't guarantee we abide by our "
1099 "min-sizing function.";
1100 track->growSizeDuringDistribution(growthShare);
1101 availableLogicalSpace -= growthShare;
1102 }
1103 }
1104
1105 for (auto* track : tracks) {
1106 track->setPlannedSize(
1107 track->plannedSize() == infinity
1108 ? track->sizeDuringDistribution()
1109 : std::max(track->plannedSize(), track->sizeDuringDistribution()));
1110 }
1111 }
1112
1113 template <TrackSizeComputationPhase phase>
1114 void GridTrackSizingAlgorithm::increaseSizesToAccommodateSpanningItems(
1115 const GridItemsSpanGroupRange& gridItemsWithSpan) {
1116 Vector<GridTrack>& allTracks = tracks(m_direction);
1117 for (const auto& trackIndex : m_contentSizedTracksIndex) {
1118 GridTrack& track = allTracks[trackIndex];
1119 track.setPlannedSize(
1120 trackSizeForTrackSizeComputationPhase(phase, track, AllowInfinity));
1121 }
1122
1123 Vector<GridTrack*> growBeyondGrowthLimitsTracks;
1124 Vector<GridTrack*> filteredTracks;
1125 for (auto it = gridItemsWithSpan.rangeStart; it != gridItemsWithSpan.rangeEnd;
1126 ++it) {
1127 GridItemWithSpan& gridItemWithSpan = *it;
1128 DCHECK_GT(gridItemWithSpan.getGridSpan().integerSpan(), 1u);
1129 const GridSpan& itemSpan = gridItemWithSpan.getGridSpan();
1130
1131 growBeyondGrowthLimitsTracks.shrink(0);
1132 filteredTracks.shrink(0);
1133 LayoutUnit spanningTracksSize;
1134 for (const auto& trackPosition : itemSpan) {
1135 GridTrackSize trackSize = gridTrackSize(m_direction, trackPosition);
1136 GridTrack& track = tracks(m_direction)[trackPosition];
1137 spanningTracksSize +=
1138 trackSizeForTrackSizeComputationPhase(phase, track, ForbidInfinity);
1139 if (!shouldProcessTrackForTrackSizeComputationPhase(phase, trackSize))
1140 continue;
1141
1142 filteredTracks.append(&track);
1143
1144 if (trackShouldGrowBeyondGrowthLimitsForTrackSizeComputationPhase(
1145 phase, trackSize))
1146 growBeyondGrowthLimitsTracks.append(&track);
1147 }
1148
1149 if (filteredTracks.isEmpty())
1150 continue;
1151
1152 spanningTracksSize +=
1153 m_layoutGrid->guttersSize(m_grid, m_direction, itemSpan.startLine(),
1154 itemSpan.integerSpan(), m_sizingOperation);
1155
1156 LayoutUnit extraSpace = itemSizeForTrackSizeComputationPhase(
1157 phase, gridItemWithSpan.gridItem()) -
1158 spanningTracksSize;
1159 extraSpace = extraSpace.clampNegativeToZero();
1160 auto& tracksToGrowBeyondGrowthLimits =
1161 growBeyondGrowthLimitsTracks.isEmpty() ? filteredTracks
1162 : growBeyondGrowthLimitsTracks;
1163 distributeSpaceToTracks<phase>(filteredTracks,
1164 &tracksToGrowBeyondGrowthLimits, extraSpace);
1165 }
1166
1167 for (const auto& trackIndex : m_contentSizedTracksIndex) {
1168 GridTrack& track = allTracks[trackIndex];
1169 markAsInfinitelyGrowableForTrackSizeComputationPhase(phase, track);
1170 updateTrackSizeForTrackSizeComputationPhase(phase, track);
1171 }
1172 }
1173
1174 void GridTrackSizingAlgorithm::resolveIntrinsicTrackSizes() {
1175 Vector<GridItemWithSpan> itemsSortedByIncreasingSpan;
1176 if (m_grid.hasGridItems()) {
1177 HashSet<LayoutBox*> itemsSet;
1178 for (const auto& trackIndex : m_contentSizedTracksIndex) {
1179 GridIterator iterator(m_grid, m_direction, trackIndex);
1180 GridTrack& track = tracks(m_direction)[trackIndex];
1181 while (LayoutBox* gridItem = iterator.nextGridItem()) {
1182 if (itemsSet.add(gridItem).isNewEntry) {
1183 const GridSpan& span = m_grid.gridItemSpan(*gridItem, m_direction);
1184 if (span.integerSpan() == 1) {
1185 sizeTrackToFitNonSpanningItem(span, *gridItem, track);
1186 } else if (!spanningItemCrossesFlexibleSizedTracks(span)) {
1187 itemsSortedByIncreasingSpan.append(
1188 GridItemWithSpan(*gridItem, span));
1189 }
1190 }
1191 }
1192 }
1193 std::sort(itemsSortedByIncreasingSpan.begin(),
1194 itemsSortedByIncreasingSpan.end());
1195 }
1196
1197 auto it = itemsSortedByIncreasingSpan.begin();
1198 auto end = itemsSortedByIncreasingSpan.end();
1199 while (it != end) {
1200 GridItemsSpanGroupRange spanGroupRange = {it,
1201 std::upper_bound(it, end, *it)};
1202 increaseSizesToAccommodateSpanningItems<ResolveIntrinsicMinimums>(
1203 spanGroupRange);
1204 increaseSizesToAccommodateSpanningItems<ResolveContentBasedMinimums>(
1205 spanGroupRange);
1206 increaseSizesToAccommodateSpanningItems<ResolveMaxContentMinimums>(
1207 spanGroupRange);
1208 increaseSizesToAccommodateSpanningItems<ResolveIntrinsicMaximums>(
1209 spanGroupRange);
1210 increaseSizesToAccommodateSpanningItems<ResolveMaxContentMaximums>(
1211 spanGroupRange);
1212 it = spanGroupRange.rangeEnd;
1213 }
1214
1215 for (const auto& trackIndex : m_contentSizedTracksIndex) {
1216 GridTrack& track = tracks(m_direction)[trackIndex];
1217 if (track.growthLimit() == infinity)
1218 track.setGrowthLimit(track.baseSize());
1219 }
1220 }
1221
1222 void GridTrackSizingAlgorithm::computeGridContainerIntrinsicSizes() {
1223 m_minContentSize = m_maxContentSize = LayoutUnit();
1224
1225 Vector<GridTrack>& allTracks = tracks(m_direction);
1226 for (auto& track : allTracks) {
1227 DCHECK(!track.infiniteGrowthPotential());
1228 m_minContentSize += track.baseSize();
1229 m_maxContentSize += track.growthLimit();
1230 // The growth limit caps must be cleared now in order to properly sort
1231 // tracks by growth potential on an eventual "Maximize Tracks".
1232 track.setGrowthLimitCap(WTF::nullopt);
1233 }
1234 }
1235
1236 LayoutUnit GridTrackSizingAlgorithm::computeTrackBasedSize() const {
1237 LayoutUnit size;
1238
1239 const Vector<GridTrack>& allTracks = tracks(m_direction);
1240 for (auto& track : allTracks)
1241 size += track.baseSize();
1242
1243 size += m_layoutGrid->guttersSize(m_grid, m_direction, 0, allTracks.size(),
1244 m_sizingOperation);
1245
1246 return size;
1247 }
1248
1249 double GridTrackSizingAlgorithm::findFrUnitSize(
1250 const GridSpan& tracksSpan,
1251 LayoutUnit leftOverSpace) const {
1252 if (leftOverSpace <= 0)
1253 return 0;
1254
1255 const Vector<GridTrack>& allTracks = tracks(m_direction);
1256 double flexFactorSum = 0;
1257 Vector<size_t, 8> flexibleTracksIndexes;
1258 for (const auto& trackIndex : tracksSpan) {
1259 GridTrackSize trackSize = gridTrackSize(m_direction, trackIndex);
1260 if (!trackSize.maxTrackBreadth().isFlex()) {
1261 leftOverSpace -= allTracks[trackIndex].baseSize();
1262 } else {
1263 flexibleTracksIndexes.append(trackIndex);
1264 flexFactorSum += trackSize.maxTrackBreadth().flex();
1265 }
1266 }
1267
1268 // The function is not called if we don't have <flex> grid tracks
1269 DCHECK(!flexibleTracksIndexes.isEmpty());
1270
1271 return computeFlexFactorUnitSize(allTracks, flexFactorSum, leftOverSpace,
1272 flexibleTracksIndexes);
1273 }
1274
1275 double GridTrackSizingAlgorithm::computeFlexFactorUnitSize(
1276 const Vector<GridTrack>& tracks,
1277 double flexFactorSum,
1278 LayoutUnit& leftOverSpace,
1279 const Vector<size_t, 8>& flexibleTracksIndexes,
1280 std::unique_ptr<TrackIndexSet> tracksToTreatAsInflexible) const {
1281 // We want to avoid the effect of flex factors sum below 1 making the factor
1282 // unit size to grow exponentially.
1283 double hypotheticalFactorUnitSize =
1284 leftOverSpace / std::max<double>(1, flexFactorSum);
1285
1286 // product of the hypothetical "flex factor unit" and any flexible track's
1287 // "flex factor" must be grater than such track's "base size".
1288 std::unique_ptr<TrackIndexSet> additionalTracksToTreatAsInflexible =
1289 std::move(tracksToTreatAsInflexible);
1290 bool validFlexFactorUnit = true;
1291 for (auto index : flexibleTracksIndexes) {
1292 if (additionalTracksToTreatAsInflexible &&
1293 additionalTracksToTreatAsInflexible->contains(index))
1294 continue;
1295 LayoutUnit baseSize = tracks[index].baseSize();
1296 double flexFactor =
1297 gridTrackSize(m_direction, index).maxTrackBreadth().flex();
1298 // treating all such tracks as inflexible.
1299 if (baseSize > hypotheticalFactorUnitSize * flexFactor) {
1300 leftOverSpace -= baseSize;
1301 flexFactorSum -= flexFactor;
1302 if (!additionalTracksToTreatAsInflexible)
1303 additionalTracksToTreatAsInflexible = WTF::makeUnique<TrackIndexSet>();
1304 additionalTracksToTreatAsInflexible->add(index);
1305 validFlexFactorUnit = false;
1306 }
1307 }
1308 if (!validFlexFactorUnit) {
1309 return computeFlexFactorUnitSize(
1310 tracks, flexFactorSum, leftOverSpace, flexibleTracksIndexes,
1311 std::move(additionalTracksToTreatAsInflexible));
1312 }
1313 return hypotheticalFactorUnitSize;
1314 }
1315
1316 void GridTrackSizingAlgorithm::computeFlexSizedTracksGrowth(
1317 double flexFraction,
1318 Vector<LayoutUnit>& increments,
1319 LayoutUnit& totalGrowth) const {
1320 size_t numFlexTracks = m_flexibleSizedTracksIndex.size();
1321 DCHECK_EQ(increments.size(), numFlexTracks);
1322 const Vector<GridTrack>& allTracks = tracks(m_direction);
1323 for (size_t i = 0; i < numFlexTracks; ++i) {
1324 size_t trackIndex = m_flexibleSizedTracksIndex[i];
1325 auto trackSize = gridTrackSize(m_direction, trackIndex);
1326 DCHECK(trackSize.maxTrackBreadth().isFlex());
1327 LayoutUnit oldBaseSize = allTracks[trackIndex].baseSize();
1328 LayoutUnit newBaseSize =
1329 std::max(oldBaseSize,
1330 LayoutUnit(flexFraction * trackSize.maxTrackBreadth().flex()));
1331 increments[i] = newBaseSize - oldBaseSize;
1332 totalGrowth += increments[i];
1333 }
1334 }
1335
1336 void GridTrackSizingAlgorithm::stretchFlexibleTracks(LayoutUnit freeSpace) {
1337 double flexFraction = m_strategy->findUsedFlexFraction(
1338 m_flexibleSizedTracksIndex, m_direction, freeSpace);
1339
1340 LayoutUnit totalGrowth;
1341 Vector<LayoutUnit> increments;
1342 increments.grow(m_flexibleSizedTracksIndex.size());
1343 computeFlexSizedTracksGrowth(flexFraction, increments, totalGrowth);
1344
1345 if (m_strategy->recomputeUsedFlexFractionIfNeeded(
1346 m_flexibleSizedTracksIndex, flexFraction, increments, totalGrowth)) {
1347 totalGrowth = LayoutUnit(0);
1348 computeFlexSizedTracksGrowth(flexFraction, increments, totalGrowth);
1349 }
1350
1351 size_t i = 0;
1352 Vector<GridTrack>& allTracks = tracks(m_direction);
1353 for (auto trackIndex : m_flexibleSizedTracksIndex) {
1354 auto& track = allTracks[trackIndex];
1355 if (LayoutUnit increment = increments[i++])
1356 track.setBaseSize(track.baseSize() + increment);
1357 }
1358 this->freeSpace(m_direction) -= totalGrowth;
1359 m_maxContentSize += totalGrowth;
1360 }
1361
1362 void GridTrackSizingAlgorithm::advanceNextState() {
1363 switch (m_sizingState) {
1364 case ColumnSizingFirstIteration:
1365 m_sizingState = RowSizingFirstIteration;
1366 return;
1367 case RowSizingFirstIteration:
1368 m_sizingState = ColumnSizingSecondIteration;
1369 return;
1370 case ColumnSizingSecondIteration:
1371 m_sizingState = RowSizingSecondIteration;
1372 return;
1373 case RowSizingSecondIteration:
1374 m_sizingState = ColumnSizingFirstIteration;
1375 return;
1376 }
1377 NOTREACHED();
1378 m_sizingState = ColumnSizingFirstIteration;
1379 }
1380
1381 bool GridTrackSizingAlgorithm::isValidTransition() const {
1382 switch (m_sizingState) {
1383 case ColumnSizingFirstIteration:
1384 case ColumnSizingSecondIteration:
1385 return m_direction == ForColumns;
1386 case RowSizingFirstIteration:
1387 case RowSizingSecondIteration:
1388 return m_direction == ForRows;
1389 }
1390 NOTREACHED();
1391 return false;
1392 }
1393
1394 // Described in https://drafts.csswg.org/css-grid/#algo-track-sizing
1395 void GridTrackSizingAlgorithm::run() {
1396 GridTrackSizingAlgorithmMachineState machineState(*this);
1397
1398 // Step 1.
1399 LayoutUnit initialFreeSpace = freeSpace(m_direction);
1400 initializeTrackSizes();
1401
1402 // Step 2.
1403 if (!m_contentSizedTracksIndex.isEmpty())
1404 resolveIntrinsicTrackSizes();
1405
1406 // This is not exactly a step of the track sizing algorithm, but we use the
1407 // track sizes computed
1408 // up to this moment (before maximization) to calculate the grid container
1409 // intrinsic sizes.
1410 computeGridContainerIntrinsicSizes();
1411 freeSpace(m_direction) -= m_minContentSize;
1412
1413 if (m_sizingOperation == TrackSizing && freeSpace(m_direction) <= 0)
1414 return;
1415
1416 // Step 3.
1417 m_strategy->maximizeTracks(tracks(m_direction), freeSpace(m_direction));
1418
1419 if (m_flexibleSizedTracksIndex.isEmpty())
1420 return;
1421
1422 // Step 4.
1423 stretchFlexibleTracks(initialFreeSpace);
1424 }
1425
1426 void GridTrackSizingAlgorithm::reset() {
1427 m_sizingState = ColumnSizingFirstIteration;
1428 m_columns.shrink(0);
1429 m_rows.shrink(0);
1430 m_contentSizedTracksIndex.shrink(0);
1431 m_flexibleSizedTracksIndex.shrink(0);
1432 }
1433
1434 #if DCHECK_IS_ON()
1435 bool GridTrackSizingAlgorithm::tracksAreWiderThanMinTrackBreadth() const {
1436 const Vector<GridTrack>& allTracks = tracks(m_direction);
1437 for (size_t i = 0; i < allTracks.size(); ++i) {
1438 GridTrackSize trackSize = gridTrackSize(m_direction, i);
1439 if (initialBaseSize(trackSize) > allTracks[i].baseSize())
1440 return false;
1441 }
1442 return true;
1443 }
1444 #endif
1445 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698