1 | /* |
2 | * Copyright (C) 2017 Igalia S.L. |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions |
6 | * are met: |
7 | * 1. Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. |
9 | * 2. Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. |
12 | * |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ |
25 | |
26 | #include "config.h" |
27 | #include "GridTrackSizingAlgorithm.h" |
28 | |
29 | #include "Grid.h" |
30 | #include "GridArea.h" |
31 | #include "GridLayoutFunctions.h" |
32 | #include "RenderGrid.h" |
33 | |
34 | namespace WebCore { |
35 | |
36 | const LayoutUnit& GridTrack::baseSize() const |
37 | { |
38 | ASSERT(isGrowthLimitBiggerThanBaseSize()); |
39 | return m_baseSize; |
40 | } |
41 | |
42 | const LayoutUnit& GridTrack::growthLimit() const |
43 | { |
44 | ASSERT(isGrowthLimitBiggerThanBaseSize()); |
45 | ASSERT(!m_growthLimitCap || m_growthLimitCap.value() >= m_growthLimit || m_baseSize >= m_growthLimitCap.value()); |
46 | return m_growthLimit; |
47 | } |
48 | |
49 | void GridTrack::setBaseSize(LayoutUnit baseSize) |
50 | { |
51 | m_baseSize = baseSize; |
52 | ensureGrowthLimitIsBiggerThanBaseSize(); |
53 | } |
54 | |
55 | void GridTrack::setGrowthLimit(LayoutUnit growthLimit) |
56 | { |
57 | m_growthLimit = growthLimit == infinity ? growthLimit : std::min(growthLimit, m_growthLimitCap.valueOr(growthLimit)); |
58 | ensureGrowthLimitIsBiggerThanBaseSize(); |
59 | } |
60 | |
61 | const LayoutUnit& GridTrack::growthLimitIfNotInfinite() const |
62 | { |
63 | ASSERT(isGrowthLimitBiggerThanBaseSize()); |
64 | return m_growthLimit == infinity ? m_baseSize : m_growthLimit; |
65 | } |
66 | |
67 | void GridTrack::setTempSize(const LayoutUnit& tempSize) |
68 | { |
69 | ASSERT(tempSize >= 0); |
70 | ASSERT(growthLimitIsInfinite() || growthLimit() >= tempSize); |
71 | m_tempSize = tempSize; |
72 | } |
73 | |
74 | void GridTrack::growTempSize(const LayoutUnit& tempSize) |
75 | { |
76 | ASSERT(tempSize >= 0); |
77 | m_tempSize += tempSize; |
78 | } |
79 | |
80 | void GridTrack::setGrowthLimitCap(Optional<LayoutUnit> growthLimitCap) |
81 | { |
82 | ASSERT(!growthLimitCap || growthLimitCap.value() >= 0); |
83 | m_growthLimitCap = growthLimitCap; |
84 | } |
85 | |
86 | void GridTrack::ensureGrowthLimitIsBiggerThanBaseSize() |
87 | { |
88 | if (m_growthLimit != infinity && m_growthLimit < m_baseSize) |
89 | m_growthLimit = m_baseSize; |
90 | } |
91 | |
92 | // Static helper methods. |
93 | |
94 | static GridAxis gridAxisForDirection(GridTrackSizingDirection direction) |
95 | { |
96 | return direction == ForColumns ? GridRowAxis : GridColumnAxis; |
97 | } |
98 | |
99 | static GridTrackSizingDirection gridDirectionForAxis(GridAxis axis) |
100 | { |
101 | return axis == GridRowAxis ? ForColumns : ForRows; |
102 | } |
103 | |
104 | static bool shouldClearOverrideContainingBlockContentSizeForChild(const RenderBox& child, GridTrackSizingDirection direction) |
105 | { |
106 | if (direction == ForColumns) |
107 | return child.hasRelativeLogicalWidth() || child.style().logicalWidth().isIntrinsicOrAuto(); |
108 | return child.hasRelativeLogicalHeight() || child.style().logicalHeight().isIntrinsicOrAuto(); |
109 | } |
110 | |
111 | static void setOverrideContainingBlockContentSizeForChild(RenderBox& child, GridTrackSizingDirection direction, Optional<LayoutUnit> size) |
112 | { |
113 | if (direction == ForColumns) |
114 | child.setOverrideContainingBlockContentLogicalWidth(size); |
115 | else |
116 | child.setOverrideContainingBlockContentLogicalHeight(size); |
117 | } |
118 | |
119 | // FIXME: we borrowed this from RenderBlock. We cannot call it from here because it's protected for RenderObjects. |
120 | static LayoutUnit marginIntrinsicLogicalWidthForChild(const RenderGrid* renderGrid, RenderBox& child) |
121 | { |
122 | // A margin has three types: fixed, percentage, and auto (variable). |
123 | // Auto and percentage margins become 0 when computing min/max width. |
124 | // Fixed margins can be added in as is. |
125 | Length marginLeft = child.style().marginStartUsing(&renderGrid->style()); |
126 | Length marginRight = child.style().marginEndUsing(&renderGrid->style()); |
127 | LayoutUnit margin; |
128 | if (marginLeft.isFixed()) |
129 | margin += marginLeft.value(); |
130 | if (marginRight.isFixed()) |
131 | margin += marginRight.value(); |
132 | return margin; |
133 | } |
134 | |
135 | // GridTrackSizingAlgorithm private. |
136 | |
137 | void GridTrackSizingAlgorithm::setFreeSpace(GridTrackSizingDirection direction, Optional<LayoutUnit> freeSpace) |
138 | { |
139 | if (direction == ForColumns) |
140 | m_freeSpaceColumns = freeSpace; |
141 | else |
142 | m_freeSpaceRows = freeSpace; |
143 | } |
144 | |
145 | Optional<LayoutUnit> GridTrackSizingAlgorithm::availableSpace() const |
146 | { |
147 | ASSERT(wasSetup()); |
148 | return availableSpace(m_direction); |
149 | } |
150 | |
151 | void GridTrackSizingAlgorithm::setAvailableSpace(GridTrackSizingDirection direction, Optional<LayoutUnit> availableSpace) |
152 | { |
153 | if (direction == ForColumns) |
154 | m_availableSpaceColumns = availableSpace; |
155 | else |
156 | m_availableSpaceRows = availableSpace; |
157 | } |
158 | |
159 | const GridTrackSize& GridTrackSizingAlgorithm::rawGridTrackSize(GridTrackSizingDirection direction, unsigned translatedIndex) const |
160 | { |
161 | bool isRowAxis = direction == ForColumns; |
162 | auto& renderStyle = m_renderGrid->style(); |
163 | auto& trackStyles = isRowAxis ? renderStyle.gridColumns() : renderStyle.gridRows(); |
164 | auto& autoRepeatTrackStyles = isRowAxis ? renderStyle.gridAutoRepeatColumns() : renderStyle.gridAutoRepeatRows(); |
165 | auto& autoTrackStyles = isRowAxis ? renderStyle.gridAutoColumns() : renderStyle.gridAutoRows(); |
166 | unsigned insertionPoint = isRowAxis ? renderStyle.gridAutoRepeatColumnsInsertionPoint() : renderStyle.gridAutoRepeatRowsInsertionPoint(); |
167 | unsigned autoRepeatTracksCount = m_grid.autoRepeatTracks(direction); |
168 | |
169 | // We should not use GridPositionsResolver::explicitGridXXXCount() for this because the |
170 | // explicit grid might be larger than the number of tracks in grid-template-rows|columns (if |
171 | // grid-template-areas is specified for example). |
172 | unsigned explicitTracksCount = trackStyles.size() + autoRepeatTracksCount; |
173 | |
174 | int untranslatedIndexAsInt = translatedIndex + m_grid.smallestTrackStart(direction); |
175 | unsigned autoTrackStylesSize = autoTrackStyles.size(); |
176 | if (untranslatedIndexAsInt < 0) { |
177 | int index = untranslatedIndexAsInt % static_cast<int>(autoTrackStylesSize); |
178 | // We need to traspose the index because the first negative implicit line will get the last defined auto track and so on. |
179 | index += index ? autoTrackStylesSize : 0; |
180 | ASSERT(index >= 0); |
181 | return autoTrackStyles[index]; |
182 | } |
183 | |
184 | unsigned untranslatedIndex = static_cast<unsigned>(untranslatedIndexAsInt); |
185 | if (untranslatedIndex >= explicitTracksCount) |
186 | return autoTrackStyles[(untranslatedIndex - explicitTracksCount) % autoTrackStylesSize]; |
187 | |
188 | if (!autoRepeatTracksCount || untranslatedIndex < insertionPoint) |
189 | return trackStyles[untranslatedIndex]; |
190 | |
191 | if (untranslatedIndex < (insertionPoint + autoRepeatTracksCount)) { |
192 | unsigned autoRepeatLocalIndex = untranslatedIndexAsInt - insertionPoint; |
193 | return autoRepeatTrackStyles[autoRepeatLocalIndex % autoRepeatTrackStyles.size()]; |
194 | } |
195 | |
196 | return trackStyles[untranslatedIndex - autoRepeatTracksCount]; |
197 | } |
198 | |
199 | LayoutUnit GridTrackSizingAlgorithm::computeTrackBasedSize() const |
200 | { |
201 | LayoutUnit size; |
202 | auto& allTracks = tracks(m_direction); |
203 | for (auto& track : allTracks) |
204 | size += track.baseSize(); |
205 | |
206 | size += m_renderGrid->guttersSize(m_grid, m_direction, 0, allTracks.size(), availableSpace()); |
207 | |
208 | return size; |
209 | } |
210 | |
211 | LayoutUnit GridTrackSizingAlgorithm::initialBaseSize(const GridTrackSize& trackSize) const |
212 | { |
213 | const GridLength& gridLength = trackSize.minTrackBreadth(); |
214 | if (gridLength.isFlex()) |
215 | return 0; |
216 | |
217 | const Length& trackLength = gridLength.length(); |
218 | if (trackLength.isSpecified()) |
219 | return valueForLength(trackLength, std::max<LayoutUnit>(availableSpace().valueOr(0), 0)); |
220 | |
221 | ASSERT(trackLength.isMinContent() || trackLength.isAuto() || trackLength.isMaxContent()); |
222 | return 0; |
223 | } |
224 | |
225 | LayoutUnit GridTrackSizingAlgorithm::initialGrowthLimit(const GridTrackSize& trackSize, LayoutUnit baseSize) const |
226 | { |
227 | const GridLength& gridLength = trackSize.maxTrackBreadth(); |
228 | if (gridLength.isFlex()) |
229 | return baseSize; |
230 | |
231 | const Length& trackLength = gridLength.length(); |
232 | if (trackLength.isSpecified()) |
233 | return valueForLength(trackLength, std::max<LayoutUnit>(availableSpace().valueOr(0), 0)); |
234 | |
235 | ASSERT(trackLength.isMinContent() || trackLength.isAuto() || trackLength.isMaxContent()); |
236 | return infinity; |
237 | } |
238 | |
239 | void GridTrackSizingAlgorithm::sizeTrackToFitNonSpanningItem(const GridSpan& span, RenderBox& gridItem, GridTrack& track) |
240 | { |
241 | unsigned trackPosition = span.startLine(); |
242 | GridTrackSize trackSize = gridTrackSize(m_direction, trackPosition); |
243 | |
244 | if (trackSize.hasMinContentMinTrackBreadth()) { |
245 | track.setBaseSize(std::max(track.baseSize(), m_strategy->minContentForChild(gridItem))); |
246 | } else if (trackSize.hasMaxContentMinTrackBreadth()) { |
247 | track.setBaseSize(std::max(track.baseSize(), m_strategy->maxContentForChild(gridItem))); |
248 | } else if (trackSize.hasAutoMinTrackBreadth()) { |
249 | track.setBaseSize(std::max(track.baseSize(), m_strategy->minSizeForChild(gridItem))); |
250 | } |
251 | |
252 | if (trackSize.hasMinContentMaxTrackBreadth()) { |
253 | track.setGrowthLimit(std::max(track.growthLimit(), m_strategy->minContentForChild(gridItem))); |
254 | } else if (trackSize.hasMaxContentOrAutoMaxTrackBreadth()) { |
255 | LayoutUnit growthLimit = m_strategy->maxContentForChild(gridItem); |
256 | if (trackSize.isFitContent()) |
257 | growthLimit = std::min(growthLimit, valueForLength(trackSize.fitContentTrackBreadth().length(), availableSpace().valueOr(0))); |
258 | track.setGrowthLimit(std::max(track.growthLimit(), growthLimit)); |
259 | } |
260 | } |
261 | |
262 | bool GridTrackSizingAlgorithm::spanningItemCrossesFlexibleSizedTracks(const GridSpan& itemSpan) const |
263 | { |
264 | for (auto trackPosition : itemSpan) { |
265 | const GridTrackSize& trackSize = gridTrackSize(m_direction, trackPosition); |
266 | if (trackSize.minTrackBreadth().isFlex() || trackSize.maxTrackBreadth().isFlex()) |
267 | return true; |
268 | } |
269 | |
270 | return false; |
271 | } |
272 | |
273 | class GridItemWithSpan { |
274 | public: |
275 | GridItemWithSpan(RenderBox& gridItem, GridSpan span) |
276 | : m_gridItem(gridItem) |
277 | , m_span(span) |
278 | { |
279 | } |
280 | |
281 | RenderBox& gridItem() const { return m_gridItem; } |
282 | GridSpan span() const { return m_span; } |
283 | |
284 | bool operator<(const GridItemWithSpan other) const { return m_span.integerSpan() < other.m_span.integerSpan(); } |
285 | |
286 | private: |
287 | std::reference_wrapper<RenderBox> m_gridItem; |
288 | GridSpan m_span; |
289 | }; |
290 | |
291 | struct GridItemsSpanGroupRange { |
292 | Vector<GridItemWithSpan>::iterator rangeStart; |
293 | Vector<GridItemWithSpan>::iterator rangeEnd; |
294 | }; |
295 | |
296 | enum TrackSizeRestriction { |
297 | AllowInfinity, |
298 | ForbidInfinity, |
299 | }; |
300 | |
301 | LayoutUnit GridTrackSizingAlgorithm::itemSizeForTrackSizeComputationPhase(TrackSizeComputationPhase phase, RenderBox& gridItem) const |
302 | { |
303 | switch (phase) { |
304 | case ResolveIntrinsicMinimums: |
305 | case ResolveIntrinsicMaximums: |
306 | return m_strategy->minSizeForChild(gridItem); |
307 | case ResolveContentBasedMinimums: |
308 | return m_strategy->minContentForChild(gridItem); |
309 | case ResolveMaxContentMinimums: |
310 | case ResolveMaxContentMaximums: |
311 | return m_strategy->maxContentForChild(gridItem); |
312 | case MaximizeTracks: |
313 | ASSERT_NOT_REACHED(); |
314 | return 0; |
315 | } |
316 | |
317 | ASSERT_NOT_REACHED(); |
318 | return 0; |
319 | } |
320 | |
321 | static bool shouldProcessTrackForTrackSizeComputationPhase(TrackSizeComputationPhase phase, const GridTrackSize& trackSize) |
322 | { |
323 | switch (phase) { |
324 | case ResolveIntrinsicMinimums: |
325 | return trackSize.hasIntrinsicMinTrackBreadth(); |
326 | case ResolveContentBasedMinimums: |
327 | return trackSize.hasMinOrMaxContentMinTrackBreadth(); |
328 | case ResolveMaxContentMinimums: |
329 | return trackSize.hasMaxContentMinTrackBreadth(); |
330 | case ResolveIntrinsicMaximums: |
331 | return trackSize.hasIntrinsicMaxTrackBreadth(); |
332 | case ResolveMaxContentMaximums: |
333 | return trackSize.hasMaxContentOrAutoMaxTrackBreadth(); |
334 | case MaximizeTracks: |
335 | ASSERT_NOT_REACHED(); |
336 | return false; |
337 | } |
338 | |
339 | ASSERT_NOT_REACHED(); |
340 | return false; |
341 | } |
342 | |
343 | static LayoutUnit trackSizeForTrackSizeComputationPhase(TrackSizeComputationPhase phase, GridTrack& track, TrackSizeRestriction restriction) |
344 | { |
345 | switch (phase) { |
346 | case ResolveIntrinsicMinimums: |
347 | case ResolveContentBasedMinimums: |
348 | case ResolveMaxContentMinimums: |
349 | case MaximizeTracks: |
350 | return track.baseSize(); |
351 | case ResolveIntrinsicMaximums: |
352 | case ResolveMaxContentMaximums: |
353 | return restriction == AllowInfinity ? track.growthLimit() : track.growthLimitIfNotInfinite(); |
354 | } |
355 | |
356 | ASSERT_NOT_REACHED(); |
357 | return track.baseSize(); |
358 | } |
359 | |
360 | static void updateTrackSizeForTrackSizeComputationPhase(TrackSizeComputationPhase phase, GridTrack& track) |
361 | { |
362 | switch (phase) { |
363 | case ResolveIntrinsicMinimums: |
364 | case ResolveContentBasedMinimums: |
365 | case ResolveMaxContentMinimums: |
366 | track.setBaseSize(track.plannedSize()); |
367 | return; |
368 | case ResolveIntrinsicMaximums: |
369 | case ResolveMaxContentMaximums: |
370 | track.setGrowthLimit(track.plannedSize()); |
371 | return; |
372 | case MaximizeTracks: |
373 | ASSERT_NOT_REACHED(); |
374 | return; |
375 | } |
376 | |
377 | ASSERT_NOT_REACHED(); |
378 | } |
379 | |
380 | static bool trackShouldGrowBeyondGrowthLimitsForTrackSizeComputationPhase(TrackSizeComputationPhase phase, const GridTrackSize& trackSize) |
381 | { |
382 | switch (phase) { |
383 | case ResolveIntrinsicMinimums: |
384 | case ResolveContentBasedMinimums: |
385 | return trackSize.hasAutoOrMinContentMinTrackBreadthAndIntrinsicMaxTrackBreadth(); |
386 | case ResolveMaxContentMinimums: |
387 | return trackSize.hasMaxContentMinTrackBreadthAndMaxContentMaxTrackBreadth(); |
388 | case ResolveIntrinsicMaximums: |
389 | case ResolveMaxContentMaximums: |
390 | return true; |
391 | case MaximizeTracks: |
392 | ASSERT_NOT_REACHED(); |
393 | return false; |
394 | } |
395 | |
396 | ASSERT_NOT_REACHED(); |
397 | return false; |
398 | } |
399 | |
400 | static void markAsInfinitelyGrowableForTrackSizeComputationPhase(TrackSizeComputationPhase phase, GridTrack& track) |
401 | { |
402 | switch (phase) { |
403 | case ResolveIntrinsicMinimums: |
404 | case ResolveContentBasedMinimums: |
405 | case ResolveMaxContentMinimums: |
406 | return; |
407 | case ResolveIntrinsicMaximums: |
408 | if (trackSizeForTrackSizeComputationPhase(phase, track, AllowInfinity) == infinity && track.plannedSize() != infinity) |
409 | track.setInfinitelyGrowable(true); |
410 | return; |
411 | case ResolveMaxContentMaximums: |
412 | if (track.infinitelyGrowable()) |
413 | track.setInfinitelyGrowable(false); |
414 | return; |
415 | case MaximizeTracks: |
416 | ASSERT_NOT_REACHED(); |
417 | return; |
418 | } |
419 | |
420 | ASSERT_NOT_REACHED(); |
421 | } |
422 | |
423 | template <TrackSizeComputationPhase phase> |
424 | void GridTrackSizingAlgorithm::increaseSizesToAccommodateSpanningItems(const GridItemsSpanGroupRange& gridItemsWithSpan) |
425 | { |
426 | Vector<GridTrack>& allTracks = tracks(m_direction); |
427 | for (const auto& trackIndex : m_contentSizedTracksIndex) { |
428 | GridTrack& track = allTracks[trackIndex]; |
429 | track.setPlannedSize(trackSizeForTrackSizeComputationPhase(phase, track, AllowInfinity)); |
430 | } |
431 | |
432 | Vector<GridTrack*> growBeyondGrowthLimitsTracks; |
433 | Vector<GridTrack*> filteredTracks; |
434 | for (auto it = gridItemsWithSpan.rangeStart; it != gridItemsWithSpan.rangeEnd; ++it) { |
435 | GridItemWithSpan& gridItemWithSpan = *it; |
436 | ASSERT(gridItemWithSpan.span().integerSpan() > 1); |
437 | const GridSpan& itemSpan = gridItemWithSpan.span(); |
438 | |
439 | filteredTracks.shrink(0); |
440 | growBeyondGrowthLimitsTracks.shrink(0); |
441 | LayoutUnit spanningTracksSize; |
442 | for (auto trackPosition : itemSpan) { |
443 | const GridTrackSize& trackSize = gridTrackSize(m_direction, trackPosition); |
444 | GridTrack& track = tracks(m_direction)[trackPosition]; |
445 | spanningTracksSize += trackSizeForTrackSizeComputationPhase(phase, track, ForbidInfinity); |
446 | if (!shouldProcessTrackForTrackSizeComputationPhase(phase, trackSize)) |
447 | continue; |
448 | |
449 | filteredTracks.append(&track); |
450 | |
451 | if (trackShouldGrowBeyondGrowthLimitsForTrackSizeComputationPhase(phase, trackSize)) |
452 | growBeyondGrowthLimitsTracks.append(&track); |
453 | } |
454 | |
455 | if (filteredTracks.isEmpty()) |
456 | continue; |
457 | |
458 | spanningTracksSize += m_renderGrid->guttersSize(m_grid, m_direction, itemSpan.startLine(), itemSpan.integerSpan(), availableSpace()); |
459 | |
460 | LayoutUnit = itemSizeForTrackSizeComputationPhase(phase, gridItemWithSpan.gridItem()) - spanningTracksSize; |
461 | extraSpace = std::max<LayoutUnit>(extraSpace, 0); |
462 | auto& tracksToGrowBeyondGrowthLimits = growBeyondGrowthLimitsTracks.isEmpty() ? filteredTracks : growBeyondGrowthLimitsTracks; |
463 | distributeSpaceToTracks<phase>(filteredTracks, &tracksToGrowBeyondGrowthLimits, extraSpace); |
464 | } |
465 | |
466 | for (const auto& trackIndex : m_contentSizedTracksIndex) { |
467 | GridTrack& track = allTracks[trackIndex]; |
468 | markAsInfinitelyGrowableForTrackSizeComputationPhase(phase, track); |
469 | updateTrackSizeForTrackSizeComputationPhase(phase, track); |
470 | } |
471 | } |
472 | |
473 | static bool sortByGridTrackGrowthPotential(const GridTrack* track1, const GridTrack* track2) |
474 | { |
475 | // This check ensures that we respect the irreflexivity property of the strict weak ordering required by std::sort |
476 | // (forall x: NOT x < x). |
477 | bool track1HasInfiniteGrowthPotentialWithoutCap = track1->infiniteGrowthPotential() && !track1->growthLimitCap(); |
478 | bool track2HasInfiniteGrowthPotentialWithoutCap = track2->infiniteGrowthPotential() && !track2->growthLimitCap(); |
479 | |
480 | if (track1HasInfiniteGrowthPotentialWithoutCap && track2HasInfiniteGrowthPotentialWithoutCap) |
481 | return false; |
482 | |
483 | if (track1HasInfiniteGrowthPotentialWithoutCap || track2HasInfiniteGrowthPotentialWithoutCap) |
484 | return track2HasInfiniteGrowthPotentialWithoutCap; |
485 | |
486 | LayoutUnit track1Limit = track1->growthLimitCap().valueOr(track1->growthLimit()); |
487 | LayoutUnit track2Limit = track2->growthLimitCap().valueOr(track2->growthLimit()); |
488 | return (track1Limit - track1->baseSize()) < (track2Limit - track2->baseSize()); |
489 | } |
490 | |
491 | static void clampGrowthShareIfNeeded(TrackSizeComputationPhase phase, const GridTrack& track, LayoutUnit& growthShare) |
492 | { |
493 | if (phase != ResolveMaxContentMaximums || !track.growthLimitCap()) |
494 | return; |
495 | |
496 | LayoutUnit distanceToCap = track.growthLimitCap().value() - track.tempSize(); |
497 | if (distanceToCap <= 0) |
498 | return; |
499 | |
500 | growthShare = std::min(growthShare, distanceToCap); |
501 | } |
502 | |
503 | template <TrackSizeComputationPhase phase> |
504 | void GridTrackSizingAlgorithm::distributeSpaceToTracks(Vector<GridTrack*>& tracks, Vector<GridTrack*>* growBeyondGrowthLimitsTracks, LayoutUnit& freeSpace) const |
505 | { |
506 | ASSERT(freeSpace >= 0); |
507 | |
508 | for (auto* track : tracks) |
509 | track->setTempSize(trackSizeForTrackSizeComputationPhase(phase, *track, ForbidInfinity)); |
510 | |
511 | if (freeSpace > 0) { |
512 | std::sort(tracks.begin(), tracks.end(), sortByGridTrackGrowthPotential); |
513 | |
514 | unsigned tracksSize = tracks.size(); |
515 | for (unsigned i = 0; i < tracksSize; ++i) { |
516 | GridTrack& track = *tracks[i]; |
517 | const LayoutUnit& trackBreadth = trackSizeForTrackSizeComputationPhase(phase, track, ForbidInfinity); |
518 | bool infiniteGrowthPotential = track.infiniteGrowthPotential(); |
519 | LayoutUnit trackGrowthPotential = infiniteGrowthPotential ? track.growthLimit() : track.growthLimit() - trackBreadth; |
520 | // Let's avoid computing availableLogicalSpaceShare as much as possible as it's a hot spot in performance tests. |
521 | if (trackGrowthPotential > 0 || infiniteGrowthPotential) { |
522 | LayoutUnit availableLogicalSpaceShare = freeSpace / (tracksSize - i); |
523 | LayoutUnit growthShare = infiniteGrowthPotential ? availableLogicalSpaceShare : std::min(availableLogicalSpaceShare, trackGrowthPotential); |
524 | clampGrowthShareIfNeeded(phase, track, growthShare); |
525 | ASSERT_WITH_MESSAGE(growthShare >= 0, "We should never shrink any grid track or else we can't guarantee we abide by our min-sizing function. We can still have 0 as growthShare if the amount of tracks greatly exceeds the freeSpace." ); |
526 | track.growTempSize(growthShare); |
527 | freeSpace -= growthShare; |
528 | } |
529 | } |
530 | } |
531 | |
532 | if (freeSpace > 0 && growBeyondGrowthLimitsTracks) { |
533 | // We need to sort them because there might be tracks with growth limit caps (like the ones |
534 | // with fit-content()) which cannot indefinitely grow over the limits. |
535 | if (phase == ResolveMaxContentMaximums) |
536 | std::sort(growBeyondGrowthLimitsTracks->begin(), growBeyondGrowthLimitsTracks->end(), sortByGridTrackGrowthPotential); |
537 | |
538 | unsigned tracksGrowingBeyondGrowthLimitsSize = growBeyondGrowthLimitsTracks->size(); |
539 | for (unsigned i = 0; i < tracksGrowingBeyondGrowthLimitsSize; ++i) { |
540 | GridTrack* track = growBeyondGrowthLimitsTracks->at(i); |
541 | LayoutUnit growthShare = freeSpace / (tracksGrowingBeyondGrowthLimitsSize - i); |
542 | clampGrowthShareIfNeeded(phase, *track, growthShare); |
543 | track->growTempSize(growthShare); |
544 | freeSpace -= growthShare; |
545 | } |
546 | } |
547 | |
548 | for (auto* track : tracks) |
549 | track->setPlannedSize(track->plannedSize() == infinity ? track->tempSize() : std::max(track->plannedSize(), track->tempSize())); |
550 | } |
551 | |
552 | LayoutSize GridTrackSizingAlgorithm::estimatedGridAreaBreadthForChild(const RenderBox& child) const |
553 | { |
554 | return {estimatedGridAreaBreadthForChild(child, ForColumns), estimatedGridAreaBreadthForChild(child, ForRows)}; |
555 | } |
556 | |
557 | LayoutUnit GridTrackSizingAlgorithm::estimatedGridAreaBreadthForChild(const RenderBox& child, GridTrackSizingDirection direction) const |
558 | { |
559 | const GridSpan& span = m_grid.gridItemSpan(child, direction); |
560 | LayoutUnit gridAreaSize; |
561 | bool gridAreaIsIndefinite = false; |
562 | Optional<LayoutUnit> availableSize = availableSpace(direction); |
563 | for (auto trackPosition : span) { |
564 | // We may need to estimate the grid area size before running the track |
565 | // sizing algorithm in order to perform the pre-layout of orthogonal |
566 | // items. |
567 | GridTrackSize trackSize = wasSetup() ? gridTrackSize(direction, trackPosition) : rawGridTrackSize(direction, trackPosition); |
568 | GridLength maxTrackSize = trackSize.maxTrackBreadth(); |
569 | if (maxTrackSize.isContentSized() || maxTrackSize.isFlex() || isRelativeGridLengthAsAuto(maxTrackSize, direction)) |
570 | gridAreaIsIndefinite = true; |
571 | else |
572 | gridAreaSize += valueForLength(maxTrackSize.length(), availableSize.valueOr(0_lu)); |
573 | } |
574 | |
575 | gridAreaSize += m_renderGrid->guttersSize(m_grid, direction, span.startLine(), span.integerSpan(), availableSize); |
576 | |
577 | GridTrackSizingDirection childInlineDirection = GridLayoutFunctions::flowAwareDirectionForChild(*m_renderGrid, child, ForColumns); |
578 | if (gridAreaIsIndefinite) |
579 | return direction == childInlineDirection ? std::max(child.maxPreferredLogicalWidth(), gridAreaSize) : -1_lu; |
580 | return gridAreaSize; |
581 | } |
582 | |
583 | LayoutUnit GridTrackSizingAlgorithm::gridAreaBreadthForChild(const RenderBox& child, GridTrackSizingDirection direction) const |
584 | { |
585 | bool addContentAlignmentOffset = |
586 | direction == ForColumns && m_sizingState == RowSizingFirstIteration; |
587 | // To determine the column track's size based on an orthogonal grid item we need it's logical |
588 | // height, which may depend on the row track's size. It's possible that the row tracks sizing |
589 | // logic has not been performed yet, so we will need to do an estimation. |
590 | if (direction == ForRows && (m_sizingState == ColumnSizingFirstIteration || m_sizingState == ColumnSizingSecondIteration)) { |
591 | ASSERT(GridLayoutFunctions::isOrthogonalChild(*m_renderGrid, child)); |
592 | // FIXME (jfernandez) Content Alignment should account for this heuristic. |
593 | // https://github.com/w3c/csswg-drafts/issues/2697 |
594 | if (m_sizingState == ColumnSizingFirstIteration) |
595 | return estimatedGridAreaBreadthForChild(child, ForRows); |
596 | addContentAlignmentOffset = true; |
597 | } |
598 | |
599 | const Vector<GridTrack>& allTracks = tracks(direction); |
600 | const GridSpan& span = m_grid.gridItemSpan(child, direction); |
601 | LayoutUnit gridAreaBreadth; |
602 | for (auto trackPosition : span) |
603 | gridAreaBreadth += allTracks[trackPosition].baseSize(); |
604 | |
605 | if (addContentAlignmentOffset) |
606 | gridAreaBreadth += (span.integerSpan() - 1) * m_renderGrid->gridItemOffset(direction); |
607 | |
608 | gridAreaBreadth += m_renderGrid->guttersSize(m_grid, direction, span.startLine(), span.integerSpan(), availableSpace(direction)); |
609 | |
610 | return gridAreaBreadth; |
611 | } |
612 | |
613 | bool GridTrackSizingAlgorithm::isRelativeGridLengthAsAuto(const GridLength& length, GridTrackSizingDirection direction) const |
614 | { |
615 | return length.isPercentage() && !availableSpace(direction); |
616 | } |
617 | |
618 | bool GridTrackSizingAlgorithm::isIntrinsicSizedGridArea(const RenderBox& child, GridAxis axis) const |
619 | { |
620 | ASSERT(wasSetup()); |
621 | GridTrackSizingDirection direction = gridDirectionForAxis(axis); |
622 | const GridSpan& span = m_grid.gridItemSpan(child, direction); |
623 | for (auto trackPosition : span) { |
624 | GridTrackSize trackSize = rawGridTrackSize(direction, trackPosition); |
625 | // We consider fr units as 'auto' for the min sizing function. |
626 | // FIXME(jfernandez): https://github.com/w3c/csswg-drafts/issues/2611 |
627 | // |
628 | // The use of AvailableSize function may imply different results |
629 | // for the same item when assuming indefinite or definite size |
630 | // constraints depending on the phase we evaluate the item's |
631 | // baseline participation. |
632 | // FIXME(jfernandez): https://github.com/w3c/csswg-drafts/issues/3046 |
633 | if (trackSize.isContentSized() || trackSize.isFitContent() || trackSize.minTrackBreadth().isFlex() || (trackSize.maxTrackBreadth().isFlex() && !availableSpace(direction))) |
634 | return true; |
635 | } |
636 | return false; |
637 | } |
638 | |
639 | GridTrackSize GridTrackSizingAlgorithm::gridTrackSize(GridTrackSizingDirection direction, unsigned translatedIndex) const |
640 | { |
641 | ASSERT(wasSetup()); |
642 | // Collapse empty auto repeat tracks if auto-fit. |
643 | if (m_grid.hasAutoRepeatEmptyTracks(direction) && m_grid.isEmptyAutoRepeatTrack(direction, translatedIndex)) |
644 | return { Length(Fixed), LengthTrackSizing }; |
645 | |
646 | auto& trackSize = rawGridTrackSize(direction, translatedIndex); |
647 | if (trackSize.isFitContent()) |
648 | return isRelativeGridLengthAsAuto(trackSize.fitContentTrackBreadth(), direction) ? GridTrackSize(Length(Auto), Length(MaxContent)) : trackSize; |
649 | |
650 | GridLength minTrackBreadth = trackSize.minTrackBreadth(); |
651 | GridLength maxTrackBreadth = trackSize.maxTrackBreadth(); |
652 | // If the logical width/height of the grid container is indefinite, percentage |
653 | // values are treated as <auto>. |
654 | if (isRelativeGridLengthAsAuto(trackSize.minTrackBreadth(), direction)) |
655 | minTrackBreadth = Length(Auto); |
656 | if (isRelativeGridLengthAsAuto(trackSize.maxTrackBreadth(), direction)) |
657 | maxTrackBreadth = Length(Auto); |
658 | |
659 | // Flex sizes are invalid as a min sizing function. However we still can have a flexible |minTrackBreadth| |
660 | // if the track size is just a flex size (e.g. "1fr"), the spec says that in this case it implies an automatic minimum. |
661 | if (minTrackBreadth.isFlex()) |
662 | minTrackBreadth = Length(Auto); |
663 | |
664 | return GridTrackSize(minTrackBreadth, maxTrackBreadth); |
665 | } |
666 | |
667 | double GridTrackSizingAlgorithm::computeFlexFactorUnitSize(const Vector<GridTrack>& tracks, double flexFactorSum, LayoutUnit& leftOverSpace, const Vector<unsigned, 8>& flexibleTracksIndexes, std::unique_ptr<TrackIndexSet> tracksToTreatAsInflexible) const |
668 | { |
669 | // We want to avoid the effect of flex factors sum below 1 making the factor unit size to grow exponentially. |
670 | double hypotheticalFactorUnitSize = leftOverSpace / std::max<double>(1, flexFactorSum); |
671 | |
672 | // product of the hypothetical "flex factor unit" and any flexible track's "flex factor" must be grater than such track's "base size". |
673 | bool validFlexFactorUnit = true; |
674 | for (auto index : flexibleTracksIndexes) { |
675 | if (tracksToTreatAsInflexible && tracksToTreatAsInflexible->contains(index)) |
676 | continue; |
677 | LayoutUnit baseSize = tracks[index].baseSize(); |
678 | double flexFactor = gridTrackSize(m_direction, index).maxTrackBreadth().flex(); |
679 | // treating all such tracks as inflexible. |
680 | if (baseSize > hypotheticalFactorUnitSize * flexFactor) { |
681 | leftOverSpace -= baseSize; |
682 | flexFactorSum -= flexFactor; |
683 | if (!tracksToTreatAsInflexible) |
684 | tracksToTreatAsInflexible = std::make_unique<TrackIndexSet>(); |
685 | tracksToTreatAsInflexible->add(index); |
686 | validFlexFactorUnit = false; |
687 | } |
688 | } |
689 | if (!validFlexFactorUnit) |
690 | return computeFlexFactorUnitSize(tracks, flexFactorSum, leftOverSpace, flexibleTracksIndexes, WTFMove(tracksToTreatAsInflexible)); |
691 | return hypotheticalFactorUnitSize; |
692 | } |
693 | |
694 | void GridTrackSizingAlgorithm::computeFlexSizedTracksGrowth(double flexFraction, Vector<LayoutUnit>& increments, LayoutUnit& totalGrowth) const |
695 | { |
696 | size_t = m_flexibleSizedTracksIndex.size(); |
697 | ASSERT(increments.size() == numFlexTracks); |
698 | const Vector<GridTrack>& allTracks = tracks(m_direction); |
699 | for (size_t i = 0; i < numFlexTracks; ++i) { |
700 | unsigned trackIndex = m_flexibleSizedTracksIndex[i]; |
701 | auto trackSize = gridTrackSize(m_direction, trackIndex); |
702 | ASSERT(trackSize.maxTrackBreadth().isFlex()); |
703 | LayoutUnit oldBaseSize = allTracks[trackIndex].baseSize(); |
704 | LayoutUnit newBaseSize = std::max(oldBaseSize, LayoutUnit(flexFraction * trackSize.maxTrackBreadth().flex())); |
705 | increments[i] = newBaseSize - oldBaseSize; |
706 | totalGrowth += increments[i]; |
707 | } |
708 | } |
709 | |
710 | double GridTrackSizingAlgorithm::findFrUnitSize(const GridSpan& tracksSpan, LayoutUnit leftOverSpace) const |
711 | { |
712 | if (leftOverSpace <= 0) |
713 | return 0; |
714 | |
715 | const Vector<GridTrack>& allTracks = tracks(m_direction); |
716 | double flexFactorSum = 0; |
717 | Vector<unsigned, 8> flexibleTracksIndexes; |
718 | for (auto trackIndex : tracksSpan) { |
719 | GridTrackSize trackSize = gridTrackSize(m_direction, trackIndex); |
720 | if (!trackSize.maxTrackBreadth().isFlex()) |
721 | leftOverSpace -= allTracks[trackIndex].baseSize(); |
722 | else { |
723 | double flexFactor = trackSize.maxTrackBreadth().flex(); |
724 | flexibleTracksIndexes.append(trackIndex); |
725 | flexFactorSum += flexFactor; |
726 | } |
727 | } |
728 | // We don't remove the gutters from left_over_space here, because that was already done before. |
729 | |
730 | // The function is not called if we don't have <flex> grid tracks. |
731 | ASSERT(!flexibleTracksIndexes.isEmpty()); |
732 | |
733 | return computeFlexFactorUnitSize(allTracks, flexFactorSum, leftOverSpace, flexibleTracksIndexes); |
734 | } |
735 | |
736 | void GridTrackSizingAlgorithm::computeGridContainerIntrinsicSizes() |
737 | { |
738 | m_minContentSize = m_maxContentSize = 0_lu; |
739 | |
740 | Vector<GridTrack>& allTracks = tracks(m_direction); |
741 | for (auto& track : allTracks) { |
742 | ASSERT(!track.infiniteGrowthPotential()); |
743 | m_minContentSize += track.baseSize(); |
744 | m_maxContentSize += track.growthLimit(); |
745 | // The growth limit caps must be cleared now in order to properly sort |
746 | // tracks by growth potential on an eventual "Maximize Tracks". |
747 | track.setGrowthLimitCap(WTF::nullopt); |
748 | } |
749 | } |
750 | |
751 | // GridTrackSizingAlgorithmStrategy. |
752 | LayoutUnit GridTrackSizingAlgorithmStrategy::logicalHeightForChild(RenderBox& child) const |
753 | { |
754 | GridTrackSizingDirection childBlockDirection = GridLayoutFunctions::flowAwareDirectionForChild(*renderGrid(), child, ForRows); |
755 | // If |child| has a relative logical height, we shouldn't let it override its intrinsic height, which is |
756 | // what we are interested in here. Thus we need to set the block-axis override size to -1 (no possible resolution). |
757 | if (shouldClearOverrideContainingBlockContentSizeForChild(child, ForRows)) { |
758 | setOverrideContainingBlockContentSizeForChild(child, childBlockDirection, WTF::nullopt); |
759 | child.setNeedsLayout(MarkOnlyThis); |
760 | } |
761 | |
762 | // We need to clear the stretched height to properly compute logical height during layout. |
763 | if (child.needsLayout()) |
764 | child.clearOverrideContentLogicalHeight(); |
765 | |
766 | child.layoutIfNeeded(); |
767 | return child.logicalHeight() + GridLayoutFunctions::marginLogicalSizeForChild(*renderGrid(), childBlockDirection, child) + m_algorithm.baselineOffsetForChild(child, gridAxisForDirection(direction())); |
768 | } |
769 | |
770 | LayoutUnit GridTrackSizingAlgorithmStrategy::minContentForChild(RenderBox& child) const |
771 | { |
772 | GridTrackSizingDirection childInlineDirection = GridLayoutFunctions::flowAwareDirectionForChild(*renderGrid(), child, ForColumns); |
773 | if (direction() == childInlineDirection) { |
774 | // FIXME: It's unclear if we should return the intrinsic width or the preferred width. |
775 | // See http://lists.w3.org/Archives/Public/www-style/2013Jan/0245.html |
776 | return child.minPreferredLogicalWidth() + GridLayoutFunctions::marginLogicalSizeForChild(*renderGrid(), childInlineDirection, child) + m_algorithm.baselineOffsetForChild(child, gridAxisForDirection(direction())); |
777 | } |
778 | |
779 | if (updateOverrideContainingBlockContentSizeForChild(child, childInlineDirection)) |
780 | child.setNeedsLayout(MarkOnlyThis); |
781 | return logicalHeightForChild(child); |
782 | } |
783 | |
784 | LayoutUnit GridTrackSizingAlgorithmStrategy::maxContentForChild(RenderBox& child) const |
785 | { |
786 | GridTrackSizingDirection childInlineDirection = GridLayoutFunctions::flowAwareDirectionForChild(*renderGrid(), child, ForColumns); |
787 | if (direction() == childInlineDirection) { |
788 | // FIXME: It's unclear if we should return the intrinsic width or the preferred width. |
789 | // See http://lists.w3.org/Archives/Public/www-style/2013Jan/0245.html |
790 | return child.maxPreferredLogicalWidth() + GridLayoutFunctions::marginLogicalSizeForChild(*renderGrid(), childInlineDirection, child) + m_algorithm.baselineOffsetForChild(child, gridAxisForDirection(direction())); |
791 | } |
792 | |
793 | if (updateOverrideContainingBlockContentSizeForChild(child, childInlineDirection)) |
794 | child.setNeedsLayout(MarkOnlyThis); |
795 | return logicalHeightForChild(child); |
796 | } |
797 | |
798 | LayoutUnit GridTrackSizingAlgorithmStrategy::minSizeForChild(RenderBox& child) const |
799 | { |
800 | GridTrackSizingDirection childInlineDirection = GridLayoutFunctions::flowAwareDirectionForChild(*renderGrid(), child, ForColumns); |
801 | bool isRowAxis = direction() == childInlineDirection; |
802 | const Length& childSize = isRowAxis ? child.style().logicalWidth() : child.style().logicalHeight(); |
803 | if (!childSize.isAuto()) |
804 | return minContentForChild(child); |
805 | |
806 | const Length& childMinSize = isRowAxis ? child.style().logicalMinWidth() : child.style().logicalMinHeight(); |
807 | bool overflowIsVisible = isRowAxis ? child.style().overflowInlineDirection() == Overflow::Visible : child.style().overflowBlockDirection() == Overflow::Visible; |
808 | LayoutUnit baselineShim = m_algorithm.baselineOffsetForChild(child, gridAxisForDirection(direction())); |
809 | |
810 | if (childSize.isAuto() && childMinSize.isAuto() && overflowIsVisible) { |
811 | auto minSize = minContentForChild(child); |
812 | LayoutUnit maxBreadth; |
813 | for (auto trackPosition : m_algorithm.grid().gridItemSpan(child, direction())) { |
814 | GridTrackSize trackSize = m_algorithm.gridTrackSize(direction(), trackPosition); |
815 | if (!trackSize.hasFixedMaxTrackBreadth()) |
816 | return minSize; |
817 | maxBreadth += valueForLength(trackSize.maxTrackBreadth().length(), availableSpace().valueOr(0_lu)); |
818 | } |
819 | if (minSize > maxBreadth) { |
820 | auto marginAndBorderAndPadding = GridLayoutFunctions::marginLogicalSizeForChild(*renderGrid(), direction(), child); |
821 | marginAndBorderAndPadding += isRowAxis ? child.borderAndPaddingLogicalWidth() : child.borderAndPaddingLogicalHeight(); |
822 | minSize = std::max(maxBreadth, marginAndBorderAndPadding + baselineShim); |
823 | } |
824 | return minSize; |
825 | } |
826 | |
827 | LayoutUnit gridAreaSize = m_algorithm.gridAreaBreadthForChild(child, childInlineDirection); |
828 | if (isRowAxis) |
829 | return minLogicalWidthForChild(child, childMinSize, gridAreaSize) + baselineShim; |
830 | |
831 | bool overrideSizeHasChanged = updateOverrideContainingBlockContentSizeForChild(child, childInlineDirection, gridAreaSize); |
832 | layoutGridItemForMinSizeComputation(child, overrideSizeHasChanged); |
833 | |
834 | return child.computeLogicalHeightUsing(MinSize, childMinSize, WTF::nullopt).valueOr(0) + child.marginLogicalHeight() + child.scrollbarLogicalHeight() + baselineShim; |
835 | } |
836 | |
837 | bool GridTrackSizingAlgorithm::canParticipateInBaselineAlignment(const RenderBox& child, GridAxis baselineAxis) const |
838 | { |
839 | ASSERT(baselineAxis == GridColumnAxis ? m_columnBaselineItemsMap.contains(&child) : m_rowBaselineItemsMap.contains(&child)); |
840 | |
841 | // Baseline cyclic dependencies only happen with synthesized |
842 | // baselines. These cases include orthogonal or empty grid items |
843 | // and replaced elements. |
844 | bool isParallelToBaselineAxis = baselineAxis == GridColumnAxis ? !GridLayoutFunctions::isOrthogonalChild(*m_renderGrid, child) : GridLayoutFunctions::isOrthogonalChild(*m_renderGrid, child); |
845 | if (isParallelToBaselineAxis && child.firstLineBaseline()) |
846 | return true; |
847 | |
848 | // Baseline cyclic dependencies only happen in grid areas with |
849 | // intrinsically-sized tracks. |
850 | if (!isIntrinsicSizedGridArea(child, baselineAxis)) |
851 | return true; |
852 | |
853 | return isParallelToBaselineAxis ? !child.hasRelativeLogicalHeight() : !child.hasRelativeLogicalWidth() && !child.style().logicalWidth().isAuto(); |
854 | } |
855 | |
856 | bool GridTrackSizingAlgorithm::participateInBaselineAlignment(const RenderBox& child, GridAxis baselineAxis) const |
857 | { |
858 | return baselineAxis == GridColumnAxis ? m_columnBaselineItemsMap.get(&child) : m_rowBaselineItemsMap.get(&child); |
859 | } |
860 | |
861 | void GridTrackSizingAlgorithm::updateBaselineAlignmentContext(const RenderBox& child, GridAxis baselineAxis) |
862 | { |
863 | ASSERT(wasSetup()); |
864 | ASSERT(canParticipateInBaselineAlignment(child, baselineAxis)); |
865 | ASSERT(!child.needsLayout()); |
866 | |
867 | ItemPosition align = m_renderGrid->selfAlignmentForChild(baselineAxis, child).position(); |
868 | const auto& span = m_grid.gridItemSpan(child, gridDirectionForAxis(baselineAxis)); |
869 | m_baselineAlignment.updateBaselineAlignmentContext(align, span.startLine(), child, baselineAxis); |
870 | } |
871 | |
872 | LayoutUnit GridTrackSizingAlgorithm::baselineOffsetForChild(const RenderBox& child, GridAxis baselineAxis) const |
873 | { |
874 | if (!participateInBaselineAlignment(child, baselineAxis)) |
875 | return LayoutUnit(); |
876 | |
877 | ItemPosition align = m_renderGrid->selfAlignmentForChild(baselineAxis, child).position(); |
878 | const auto& span = m_grid.gridItemSpan(child, gridDirectionForAxis(baselineAxis)); |
879 | return m_baselineAlignment.baselineOffsetForChild(align, span.startLine(), child, baselineAxis); |
880 | } |
881 | |
882 | void GridTrackSizingAlgorithm::clearBaselineItemsCache() |
883 | { |
884 | m_columnBaselineItemsMap.clear(); |
885 | m_rowBaselineItemsMap.clear(); |
886 | } |
887 | |
888 | void GridTrackSizingAlgorithm::cacheBaselineAlignedItem(const RenderBox& item, GridAxis axis) |
889 | { |
890 | ASSERT(m_renderGrid->isBaselineAlignmentForChild(item, axis)); |
891 | if (axis == GridColumnAxis) |
892 | m_columnBaselineItemsMap.add(&item, true); |
893 | else |
894 | m_rowBaselineItemsMap.add(&item, true); |
895 | } |
896 | |
897 | void GridTrackSizingAlgorithm::copyBaselineItemsCache(const GridTrackSizingAlgorithm& source, GridAxis axis) |
898 | { |
899 | if (axis == GridColumnAxis) |
900 | m_columnBaselineItemsMap = source.m_columnBaselineItemsMap; |
901 | else |
902 | m_rowBaselineItemsMap = source.m_rowBaselineItemsMap; |
903 | } |
904 | |
905 | bool GridTrackSizingAlgorithmStrategy::updateOverrideContainingBlockContentSizeForChild(RenderBox& child, GridTrackSizingDirection direction, Optional<LayoutUnit> overrideSize) const |
906 | { |
907 | if (!overrideSize) |
908 | overrideSize = m_algorithm.gridAreaBreadthForChild(child, direction); |
909 | if (GridLayoutFunctions::hasOverrideContainingBlockContentSizeForChild(child, direction) && GridLayoutFunctions::overrideContainingBlockContentSizeForChild(child, direction) == overrideSize) |
910 | return false; |
911 | |
912 | setOverrideContainingBlockContentSizeForChild(child, direction, overrideSize); |
913 | return true; |
914 | } |
915 | |
916 | class IndefiniteSizeStrategy final : public GridTrackSizingAlgorithmStrategy { |
917 | public: |
918 | IndefiniteSizeStrategy(GridTrackSizingAlgorithm& algorithm) |
919 | : GridTrackSizingAlgorithmStrategy(algorithm) { } |
920 | |
921 | private: |
922 | LayoutUnit minLogicalWidthForChild(RenderBox&, Length childMinSize, LayoutUnit availableSize) const override; |
923 | void layoutGridItemForMinSizeComputation(RenderBox&, bool overrideSizeHasChanged) const override; |
924 | void maximizeTracks(Vector<GridTrack>&, Optional<LayoutUnit>& freeSpace) override; |
925 | double findUsedFlexFraction(Vector<unsigned>& flexibleSizedTracksIndex, GridTrackSizingDirection, Optional<LayoutUnit> freeSpace) const override; |
926 | bool recomputeUsedFlexFractionIfNeeded(double& flexFraction, LayoutUnit& totalGrowth) const override; |
927 | LayoutUnit freeSpaceForStretchAutoTracksStep() const override; |
928 | }; |
929 | |
930 | LayoutUnit IndefiniteSizeStrategy::minLogicalWidthForChild(RenderBox& child, Length childMinSize, LayoutUnit availableSize) const |
931 | { |
932 | return child.computeLogicalWidthInFragmentUsing(MinSize, childMinSize, availableSize, *renderGrid(), nullptr) + marginIntrinsicLogicalWidthForChild(renderGrid(), child); |
933 | } |
934 | |
935 | void IndefiniteSizeStrategy::layoutGridItemForMinSizeComputation(RenderBox& child, bool overrideSizeHasChanged) const |
936 | { |
937 | if (overrideSizeHasChanged && direction() != ForColumns) |
938 | child.setNeedsLayout(MarkOnlyThis); |
939 | child.layoutIfNeeded(); |
940 | } |
941 | |
942 | void IndefiniteSizeStrategy::maximizeTracks(Vector<GridTrack>& tracks, Optional<LayoutUnit>& freeSpace) |
943 | { |
944 | UNUSED_PARAM(freeSpace); |
945 | for (auto& track : tracks) |
946 | track.setBaseSize(track.growthLimit()); |
947 | } |
948 | |
949 | |
950 | static inline double normalizedFlexFraction(const GridTrack& track, double flexFactor) |
951 | { |
952 | return track.baseSize() / std::max<double>(1, flexFactor); |
953 | } |
954 | |
955 | double IndefiniteSizeStrategy::findUsedFlexFraction(Vector<unsigned>& flexibleSizedTracksIndex, GridTrackSizingDirection direction, Optional<LayoutUnit> freeSpace) const |
956 | { |
957 | UNUSED_PARAM(freeSpace); |
958 | auto allTracks = m_algorithm.tracks(direction); |
959 | |
960 | double flexFraction = 0; |
961 | for (const auto& trackIndex : flexibleSizedTracksIndex) { |
962 | // FIXME: we pass TrackSizing to gridTrackSize() because it does not really matter |
963 | // as we know the track is a flex sized track. It'd be nice not to have to do that. |
964 | flexFraction = std::max(flexFraction, normalizedFlexFraction(allTracks[trackIndex], gridTrackSize(direction, trackIndex).maxTrackBreadth().flex())); |
965 | } |
966 | |
967 | const Grid& grid = m_algorithm.grid(); |
968 | if (!grid.hasGridItems()) |
969 | return flexFraction; |
970 | |
971 | for (unsigned i = 0; i < flexibleSizedTracksIndex.size(); ++i) { |
972 | GridIterator iterator(grid, direction, flexibleSizedTracksIndex[i]); |
973 | while (auto* gridItem = iterator.nextGridItem()) { |
974 | const GridSpan& span = grid.gridItemSpan(*gridItem, direction); |
975 | |
976 | // Do not include already processed items. |
977 | if (i > 0 && span.startLine() <= flexibleSizedTracksIndex[i - 1]) |
978 | continue; |
979 | |
980 | // Removing gutters from the max-content contribution of the item, so they are not taken into account in FindFrUnitSize(). |
981 | LayoutUnit leftOverSpace = maxContentForChild(*gridItem) - renderGrid()->guttersSize(m_algorithm.grid(), direction, span.startLine(), span.integerSpan(), availableSpace()); |
982 | flexFraction = std::max(flexFraction, findFrUnitSize(span, leftOverSpace)); |
983 | } |
984 | } |
985 | |
986 | return flexFraction; |
987 | } |
988 | |
989 | bool IndefiniteSizeStrategy::recomputeUsedFlexFractionIfNeeded(double& flexFraction, LayoutUnit& totalGrowth) const |
990 | { |
991 | if (direction() == ForColumns) |
992 | return false; |
993 | |
994 | const RenderGrid* renderGrid = this->renderGrid(); |
995 | |
996 | auto minSize = renderGrid->computeContentLogicalHeight(MinSize, renderGrid->style().logicalMinHeight(), WTF::nullopt); |
997 | auto maxSize = renderGrid->computeContentLogicalHeight(MaxSize, renderGrid->style().logicalMaxHeight(), WTF::nullopt); |
998 | |
999 | // Redo the flex fraction computation using min|max-height as definite available space in case |
1000 | // the total height is smaller than min-height or larger than max-height. |
1001 | LayoutUnit rowsSize = totalGrowth + computeTrackBasedSize(); |
1002 | bool checkMinSize = minSize && rowsSize < minSize.value(); |
1003 | bool checkMaxSize = maxSize && rowsSize > maxSize.value(); |
1004 | if (!checkMinSize && !checkMaxSize) |
1005 | return false; |
1006 | |
1007 | LayoutUnit freeSpace = checkMaxSize ? maxSize.value() : -1_lu; |
1008 | const Grid& grid = m_algorithm.grid(); |
1009 | freeSpace = std::max(freeSpace, minSize.value()) - renderGrid->guttersSize(grid, ForRows, 0, grid.numTracks(ForRows), availableSpace()); |
1010 | |
1011 | size_t numberOfTracks = m_algorithm.tracks(ForRows).size(); |
1012 | flexFraction = findFrUnitSize(GridSpan::translatedDefiniteGridSpan(0, numberOfTracks), freeSpace); |
1013 | return true; |
1014 | } |
1015 | |
1016 | class DefiniteSizeStrategy final : public GridTrackSizingAlgorithmStrategy { |
1017 | public: |
1018 | DefiniteSizeStrategy(GridTrackSizingAlgorithm& algorithm) |
1019 | : GridTrackSizingAlgorithmStrategy(algorithm) { } |
1020 | |
1021 | private: |
1022 | LayoutUnit minLogicalWidthForChild(RenderBox&, Length childMinSize, LayoutUnit availableSize) const override; |
1023 | void layoutGridItemForMinSizeComputation(RenderBox&, bool overrideSizeHasChanged) const override; |
1024 | void maximizeTracks(Vector<GridTrack>&, Optional<LayoutUnit>& freeSpace) override; |
1025 | double findUsedFlexFraction(Vector<unsigned>& flexibleSizedTracksIndex, GridTrackSizingDirection, Optional<LayoutUnit> freeSpace) const override; |
1026 | bool recomputeUsedFlexFractionIfNeeded(double& flexFraction, LayoutUnit& totalGrowth) const override; |
1027 | LayoutUnit freeSpaceForStretchAutoTracksStep() const override; |
1028 | }; |
1029 | |
1030 | LayoutUnit IndefiniteSizeStrategy::freeSpaceForStretchAutoTracksStep() const |
1031 | { |
1032 | ASSERT(!m_algorithm.freeSpace(direction())); |
1033 | if (direction() == ForColumns) |
1034 | return 0_lu; |
1035 | |
1036 | auto minSize = renderGrid()->computeContentLogicalHeight(MinSize, renderGrid()->style().logicalMinHeight(), WTF::nullopt); |
1037 | if (!minSize) |
1038 | return 0_lu; |
1039 | return minSize.value() - computeTrackBasedSize(); |
1040 | } |
1041 | |
1042 | LayoutUnit DefiniteSizeStrategy::minLogicalWidthForChild(RenderBox& child, Length childMinSize, LayoutUnit availableSize) const |
1043 | { |
1044 | LayoutUnit marginLogicalWidth = |
1045 | GridLayoutFunctions::computeMarginLogicalSizeForChild(*renderGrid(), ForColumns, child); |
1046 | return child.computeLogicalWidthInFragmentUsing(MinSize, childMinSize, availableSize, *renderGrid(), nullptr) + marginLogicalWidth; |
1047 | } |
1048 | |
1049 | void DefiniteSizeStrategy::maximizeTracks(Vector<GridTrack>& tracks, Optional<LayoutUnit>& freeSpace) |
1050 | { |
1051 | size_t tracksSize = tracks.size(); |
1052 | Vector<GridTrack*> tracksForDistribution(tracksSize); |
1053 | for (size_t i = 0; i < tracksSize; ++i) { |
1054 | tracksForDistribution[i] = tracks.data() + i; |
1055 | tracksForDistribution[i]->setPlannedSize(tracksForDistribution[i]->baseSize()); |
1056 | } |
1057 | |
1058 | ASSERT(freeSpace); |
1059 | distributeSpaceToTracks(tracksForDistribution, freeSpace.value()); |
1060 | |
1061 | for (auto* track : tracksForDistribution) |
1062 | track->setBaseSize(track->plannedSize()); |
1063 | } |
1064 | |
1065 | |
1066 | void DefiniteSizeStrategy::layoutGridItemForMinSizeComputation(RenderBox& child, bool overrideSizeHasChanged) const |
1067 | { |
1068 | if (overrideSizeHasChanged) |
1069 | child.setNeedsLayout(MarkOnlyThis); |
1070 | child.layoutIfNeeded(); |
1071 | } |
1072 | |
1073 | double DefiniteSizeStrategy::findUsedFlexFraction(Vector<unsigned>&, GridTrackSizingDirection direction, Optional<LayoutUnit> freeSpace) const |
1074 | { |
1075 | GridSpan allTracksSpan = GridSpan::translatedDefiniteGridSpan(0, m_algorithm.tracks(direction).size()); |
1076 | ASSERT(freeSpace); |
1077 | return findFrUnitSize(allTracksSpan, freeSpace.value()); |
1078 | } |
1079 | |
1080 | LayoutUnit DefiniteSizeStrategy::freeSpaceForStretchAutoTracksStep() const |
1081 | { |
1082 | return m_algorithm.freeSpace(direction()).value(); |
1083 | } |
1084 | |
1085 | bool DefiniteSizeStrategy::recomputeUsedFlexFractionIfNeeded(double& flexFraction, LayoutUnit& totalGrowth) const |
1086 | { |
1087 | UNUSED_PARAM(flexFraction); |
1088 | UNUSED_PARAM(totalGrowth); |
1089 | return false; |
1090 | } |
1091 | |
1092 | // GridTrackSizingAlgorithm steps. |
1093 | |
1094 | void GridTrackSizingAlgorithm::initializeTrackSizes() |
1095 | { |
1096 | ASSERT(m_contentSizedTracksIndex.isEmpty()); |
1097 | ASSERT(m_flexibleSizedTracksIndex.isEmpty()); |
1098 | ASSERT(m_autoSizedTracksForStretchIndex.isEmpty()); |
1099 | ASSERT(!m_hasPercentSizedRowsIndefiniteHeight); |
1100 | |
1101 | Vector<GridTrack>& allTracks = tracks(m_direction); |
1102 | const bool indefiniteHeight = m_direction == ForRows && !m_renderGrid->hasDefiniteLogicalHeight(); |
1103 | LayoutUnit maxSize = std::max(0_lu, availableSpace().valueOr(0_lu)); |
1104 | // 1. Initialize per Grid track variables. |
1105 | for (unsigned i = 0; i < allTracks.size(); ++i) { |
1106 | GridTrack& track = allTracks[i]; |
1107 | const GridTrackSize& trackSize = gridTrackSize(m_direction, i); |
1108 | |
1109 | track.setBaseSize(initialBaseSize(trackSize)); |
1110 | track.setGrowthLimit(initialGrowthLimit(trackSize, track.baseSize())); |
1111 | track.setInfinitelyGrowable(false); |
1112 | |
1113 | if (trackSize.isFitContent()) |
1114 | track.setGrowthLimitCap(valueForLength(trackSize.fitContentTrackBreadth().length(), maxSize)); |
1115 | if (trackSize.isContentSized()) |
1116 | m_contentSizedTracksIndex.append(i); |
1117 | if (trackSize.maxTrackBreadth().isFlex()) |
1118 | m_flexibleSizedTracksIndex.append(i); |
1119 | if (trackSize.hasAutoMaxTrackBreadth() && !trackSize.isFitContent()) |
1120 | m_autoSizedTracksForStretchIndex.append(i); |
1121 | |
1122 | if (!m_hasPercentSizedRowsIndefiniteHeight && indefiniteHeight) { |
1123 | auto& rawTrackSize = rawGridTrackSize(m_direction, i); |
1124 | if (rawTrackSize.minTrackBreadth().isPercentage() || rawTrackSize.maxTrackBreadth().isPercentage()) |
1125 | m_hasPercentSizedRowsIndefiniteHeight = true; |
1126 | } |
1127 | } |
1128 | } |
1129 | |
1130 | void GridTrackSizingAlgorithm::resolveIntrinsicTrackSizes() |
1131 | { |
1132 | Vector<GridItemWithSpan> itemsSortedByIncreasingSpan; |
1133 | HashSet<RenderBox*> itemsSet; |
1134 | Vector<GridTrack>& allTracks = tracks(m_direction); |
1135 | if (m_grid.hasGridItems()) { |
1136 | for (auto trackIndex : m_contentSizedTracksIndex) { |
1137 | GridIterator iterator(m_grid, m_direction, trackIndex); |
1138 | GridTrack& track = allTracks[trackIndex]; |
1139 | |
1140 | while (auto* gridItem = iterator.nextGridItem()) { |
1141 | if (itemsSet.add(gridItem).isNewEntry) { |
1142 | const GridSpan& span = m_grid.gridItemSpan(*gridItem, m_direction); |
1143 | if (span.integerSpan() == 1) |
1144 | sizeTrackToFitNonSpanningItem(span, *gridItem, track); |
1145 | else if (!spanningItemCrossesFlexibleSizedTracks(span)) |
1146 | itemsSortedByIncreasingSpan.append(GridItemWithSpan(*gridItem, span)); |
1147 | } |
1148 | } |
1149 | } |
1150 | std::sort(itemsSortedByIncreasingSpan.begin(), itemsSortedByIncreasingSpan.end()); |
1151 | } |
1152 | |
1153 | auto it = itemsSortedByIncreasingSpan.begin(); |
1154 | auto end = itemsSortedByIncreasingSpan.end(); |
1155 | while (it != end) { |
1156 | GridItemsSpanGroupRange spanGroupRange = { it, std::upper_bound(it, end, *it) }; |
1157 | increaseSizesToAccommodateSpanningItems<ResolveIntrinsicMinimums>(spanGroupRange); |
1158 | increaseSizesToAccommodateSpanningItems<ResolveContentBasedMinimums>(spanGroupRange); |
1159 | increaseSizesToAccommodateSpanningItems<ResolveMaxContentMinimums>(spanGroupRange); |
1160 | increaseSizesToAccommodateSpanningItems<ResolveIntrinsicMaximums>(spanGroupRange); |
1161 | increaseSizesToAccommodateSpanningItems<ResolveMaxContentMaximums>(spanGroupRange); |
1162 | it = spanGroupRange.rangeEnd; |
1163 | } |
1164 | |
1165 | for (auto trackIndex : m_contentSizedTracksIndex) { |
1166 | GridTrack& track = allTracks[trackIndex]; |
1167 | if (track.growthLimit() == infinity) |
1168 | track.setGrowthLimit(track.baseSize()); |
1169 | } |
1170 | } |
1171 | |
1172 | void GridTrackSizingAlgorithm::stretchFlexibleTracks(Optional<LayoutUnit> freeSpace) |
1173 | { |
1174 | if (m_flexibleSizedTracksIndex.isEmpty()) |
1175 | return; |
1176 | |
1177 | double flexFraction = m_strategy->findUsedFlexFraction(m_flexibleSizedTracksIndex, m_direction, freeSpace); |
1178 | |
1179 | LayoutUnit totalGrowth; |
1180 | Vector<LayoutUnit> increments; |
1181 | increments.grow(m_flexibleSizedTracksIndex.size()); |
1182 | computeFlexSizedTracksGrowth(flexFraction, increments, totalGrowth); |
1183 | |
1184 | if (m_strategy->recomputeUsedFlexFractionIfNeeded(flexFraction, totalGrowth)) { |
1185 | totalGrowth = 0_lu; |
1186 | computeFlexSizedTracksGrowth(flexFraction, increments, totalGrowth); |
1187 | } |
1188 | |
1189 | size_t i = 0; |
1190 | Vector<GridTrack>& allTracks = tracks(m_direction); |
1191 | for (auto trackIndex : m_flexibleSizedTracksIndex) { |
1192 | auto& track = allTracks[trackIndex]; |
1193 | if (LayoutUnit increment = increments[i++]) |
1194 | track.setBaseSize(track.baseSize() + increment); |
1195 | } |
1196 | if (this->freeSpace(m_direction)) |
1197 | setFreeSpace(m_direction, this->freeSpace(m_direction).value() - totalGrowth); |
1198 | m_maxContentSize += totalGrowth; |
1199 | } |
1200 | |
1201 | void GridTrackSizingAlgorithm::stretchAutoTracks() |
1202 | { |
1203 | auto currentFreeSpace = m_strategy->freeSpaceForStretchAutoTracksStep(); |
1204 | if (m_autoSizedTracksForStretchIndex.isEmpty() || currentFreeSpace <= 0 |
1205 | || (m_renderGrid->contentAlignment(m_direction).distribution() != ContentDistribution::Stretch)) |
1206 | return; |
1207 | |
1208 | Vector<GridTrack>& allTracks = tracks(m_direction); |
1209 | unsigned numberOfAutoSizedTracks = m_autoSizedTracksForStretchIndex.size(); |
1210 | LayoutUnit sizeToIncrease = currentFreeSpace / numberOfAutoSizedTracks; |
1211 | for (const auto& trackIndex : m_autoSizedTracksForStretchIndex) { |
1212 | auto& track = allTracks[trackIndex]; |
1213 | track.setBaseSize(track.baseSize() + sizeToIncrease); |
1214 | } |
1215 | setFreeSpace(m_direction, 0_lu); |
1216 | } |
1217 | |
1218 | void GridTrackSizingAlgorithm::advanceNextState() |
1219 | { |
1220 | switch (m_sizingState) { |
1221 | case ColumnSizingFirstIteration: |
1222 | m_sizingState = RowSizingFirstIteration; |
1223 | return; |
1224 | case RowSizingFirstIteration: |
1225 | m_sizingState = ColumnSizingSecondIteration; |
1226 | return; |
1227 | case ColumnSizingSecondIteration: |
1228 | m_sizingState = RowSizingSecondIteration; |
1229 | return; |
1230 | case RowSizingSecondIteration: |
1231 | m_sizingState = ColumnSizingFirstIteration; |
1232 | return; |
1233 | } |
1234 | ASSERT_NOT_REACHED(); |
1235 | m_sizingState = ColumnSizingFirstIteration; |
1236 | } |
1237 | |
1238 | bool GridTrackSizingAlgorithm::isValidTransition() const |
1239 | { |
1240 | switch (m_sizingState) { |
1241 | case ColumnSizingFirstIteration: |
1242 | case ColumnSizingSecondIteration: |
1243 | return m_direction == ForColumns; |
1244 | case RowSizingFirstIteration: |
1245 | case RowSizingSecondIteration: |
1246 | return m_direction == ForRows; |
1247 | } |
1248 | ASSERT_NOT_REACHED(); |
1249 | return false; |
1250 | } |
1251 | |
1252 | // GridTrackSizingAlgorithm API. |
1253 | |
1254 | void GridTrackSizingAlgorithm::setup(GridTrackSizingDirection direction, unsigned numTracks, SizingOperation sizingOperation, Optional<LayoutUnit> availableSpace, Optional<LayoutUnit> freeSpace) |
1255 | { |
1256 | ASSERT(m_needsSetup); |
1257 | m_direction = direction; |
1258 | setAvailableSpace(direction, availableSpace); |
1259 | |
1260 | m_sizingOperation = sizingOperation; |
1261 | switch (m_sizingOperation) { |
1262 | case IntrinsicSizeComputation: |
1263 | m_strategy = std::make_unique<IndefiniteSizeStrategy>(*this); |
1264 | break; |
1265 | case TrackSizing: |
1266 | m_strategy = std::make_unique<DefiniteSizeStrategy>(*this); |
1267 | break; |
1268 | } |
1269 | |
1270 | m_contentSizedTracksIndex.shrink(0); |
1271 | m_flexibleSizedTracksIndex.shrink(0); |
1272 | m_autoSizedTracksForStretchIndex.shrink(0); |
1273 | |
1274 | setFreeSpace(direction, freeSpace); |
1275 | tracks(direction).resize(numTracks); |
1276 | |
1277 | m_needsSetup = false; |
1278 | m_hasPercentSizedRowsIndefiniteHeight = false; |
1279 | |
1280 | computeBaselineAlignmentContext(); |
1281 | } |
1282 | |
1283 | void GridTrackSizingAlgorithm::computeBaselineAlignmentContext() |
1284 | { |
1285 | GridAxis axis = gridAxisForDirection(m_direction); |
1286 | m_baselineAlignment.clear(axis); |
1287 | m_baselineAlignment.setBlockFlow(m_renderGrid->style().writingMode()); |
1288 | BaselineItemsCache& baselineItemsCache = axis == GridColumnAxis ? m_columnBaselineItemsMap : m_rowBaselineItemsMap; |
1289 | BaselineItemsCache tmpBaselineItemsCache = baselineItemsCache; |
1290 | for (auto* child : tmpBaselineItemsCache.keys()) { |
1291 | // FIXME (jfernandez): We may have to get rid of the baseline participation |
1292 | // flag (hence just using a HashSet) depending on the CSS WG resolution on |
1293 | // https://github.com/w3c/csswg-drafts/issues/3046 |
1294 | if (canParticipateInBaselineAlignment(*child, axis)) { |
1295 | updateBaselineAlignmentContext(*child, axis); |
1296 | baselineItemsCache.set(child, true); |
1297 | } else |
1298 | baselineItemsCache.set(child, false); |
1299 | } |
1300 | } |
1301 | |
1302 | void GridTrackSizingAlgorithm::run() |
1303 | { |
1304 | ASSERT(wasSetup()); |
1305 | StateMachine stateMachine(*this); |
1306 | |
1307 | // Step 1. |
1308 | const Optional<LayoutUnit> initialFreeSpace = freeSpace(m_direction); |
1309 | initializeTrackSizes(); |
1310 | |
1311 | // Step 2. |
1312 | if (!m_contentSizedTracksIndex.isEmpty()) |
1313 | resolveIntrinsicTrackSizes(); |
1314 | |
1315 | // This is not exactly a step of the track sizing algorithm, but we use the track sizes computed |
1316 | // up to this moment (before maximization) to calculate the grid container intrinsic sizes. |
1317 | computeGridContainerIntrinsicSizes(); |
1318 | |
1319 | if (freeSpace(m_direction)) { |
1320 | LayoutUnit updatedFreeSpace = freeSpace(m_direction).value() - m_minContentSize; |
1321 | setFreeSpace(m_direction, updatedFreeSpace); |
1322 | if (updatedFreeSpace <= 0) |
1323 | return; |
1324 | } |
1325 | |
1326 | // Step 3. |
1327 | m_strategy->maximizeTracks(tracks(m_direction), m_direction == ForColumns ? m_freeSpaceColumns : m_freeSpaceRows); |
1328 | |
1329 | // Step 4. |
1330 | stretchFlexibleTracks(initialFreeSpace); |
1331 | |
1332 | // Step 5. |
1333 | stretchAutoTracks(); |
1334 | } |
1335 | |
1336 | void GridTrackSizingAlgorithm::reset() |
1337 | { |
1338 | ASSERT(wasSetup()); |
1339 | m_sizingState = ColumnSizingFirstIteration; |
1340 | m_columns.shrink(0); |
1341 | m_rows.shrink(0); |
1342 | m_contentSizedTracksIndex.shrink(0); |
1343 | m_flexibleSizedTracksIndex.shrink(0); |
1344 | m_autoSizedTracksForStretchIndex.shrink(0); |
1345 | setAvailableSpace(ForRows, WTF::nullopt); |
1346 | setAvailableSpace(ForColumns, WTF::nullopt); |
1347 | m_hasPercentSizedRowsIndefiniteHeight = false; |
1348 | } |
1349 | |
1350 | #ifndef NDEBUG |
1351 | bool GridTrackSizingAlgorithm::tracksAreWiderThanMinTrackBreadth() const |
1352 | { |
1353 | const Vector<GridTrack>& allTracks = tracks(m_direction); |
1354 | for (size_t i = 0; i < allTracks.size(); ++i) { |
1355 | GridTrackSize trackSize = gridTrackSize(m_direction, i); |
1356 | if (initialBaseSize(trackSize) > allTracks[i].baseSize()) |
1357 | return false; |
1358 | } |
1359 | return true; |
1360 | } |
1361 | #endif |
1362 | |
1363 | GridTrackSizingAlgorithm::StateMachine::StateMachine(GridTrackSizingAlgorithm& algorithm) |
1364 | : m_algorithm(algorithm) |
1365 | { |
1366 | ASSERT(m_algorithm.isValidTransition()); |
1367 | ASSERT(!m_algorithm.m_needsSetup); |
1368 | } |
1369 | |
1370 | GridTrackSizingAlgorithm::StateMachine::~StateMachine() |
1371 | { |
1372 | m_algorithm.advanceNextState(); |
1373 | m_algorithm.m_needsSetup = true; |
1374 | } |
1375 | |
1376 | } // namespace WebCore |
1377 | |