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

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

Powered by Google App Engine
This is Rietveld 408576698