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