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