| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2011 Apple Inc. All rights reserved. | |
| 3 * | |
| 4 * Redistribution and use in source and binary forms, with or without | |
| 5 * modification, are permitted provided that the following conditions | |
| 6 * are met: | |
| 7 * 1. Redistributions of source code must retain the above copyright | |
| 8 * notice, this list of conditions and the following disclaimer. | |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | |
| 10 * notice, this list of conditions and the following disclaimer in the | |
| 11 * documentation and/or other materials provided with the distribution. | |
| 12 * | |
| 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | |
| 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
| 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR | |
| 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
| 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
| 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
| 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
| 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 24 */ | |
| 25 | |
| 26 #include "config.h" | |
| 27 #include "core/rendering/RenderGrid.h" | |
| 28 | |
| 29 #include "core/layout/Layer.h" | |
| 30 #include "core/layout/TextAutosizer.h" | |
| 31 #include "core/layout/style/GridCoordinate.h" | |
| 32 #include "core/layout/style/LayoutStyle.h" | |
| 33 #include "core/paint/GridPainter.h" | |
| 34 #include "core/rendering/RenderView.h" | |
| 35 #include "platform/LengthFunctions.h" | |
| 36 | |
| 37 namespace blink { | |
| 38 | |
| 39 static const int infinity = -1; | |
| 40 | |
| 41 class GridTrack { | |
| 42 public: | |
| 43 GridTrack() | |
| 44 : m_baseSize(0) | |
| 45 , m_growthLimit(0) | |
| 46 , m_plannedIncrease(0) | |
| 47 { | |
| 48 } | |
| 49 | |
| 50 const LayoutUnit& baseSize() const | |
| 51 { | |
| 52 ASSERT(isGrowthLimitBiggerThanBaseSize()); | |
| 53 return m_baseSize; | |
| 54 } | |
| 55 | |
| 56 const LayoutUnit& growthLimit() const | |
| 57 { | |
| 58 ASSERT(isGrowthLimitBiggerThanBaseSize()); | |
| 59 return m_growthLimit; | |
| 60 } | |
| 61 | |
| 62 void setBaseSize(LayoutUnit baseSize) | |
| 63 { | |
| 64 m_baseSize = baseSize; | |
| 65 ensureGrowthLimitIsBiggerThanBaseSize(); | |
| 66 } | |
| 67 | |
| 68 void setGrowthLimit(LayoutUnit growthLimit) | |
| 69 { | |
| 70 m_growthLimit = growthLimit; | |
| 71 ensureGrowthLimitIsBiggerThanBaseSize(); | |
| 72 } | |
| 73 | |
| 74 void growBaseSize(LayoutUnit growth) | |
| 75 { | |
| 76 ASSERT(growth >= 0); | |
| 77 m_baseSize += growth; | |
| 78 ensureGrowthLimitIsBiggerThanBaseSize(); | |
| 79 } | |
| 80 | |
| 81 void growGrowthLimit(LayoutUnit growth) | |
| 82 { | |
| 83 ASSERT(growth >= 0); | |
| 84 if (m_growthLimit == infinity) | |
| 85 m_growthLimit = m_baseSize + growth; | |
| 86 else | |
| 87 m_growthLimit += growth; | |
| 88 | |
| 89 ASSERT(m_growthLimit >= m_baseSize); | |
| 90 } | |
| 91 | |
| 92 bool growthLimitIsInfinite() const | |
| 93 { | |
| 94 return m_growthLimit == infinity; | |
| 95 } | |
| 96 | |
| 97 const LayoutUnit& growthLimitIfNotInfinite() const | |
| 98 { | |
| 99 ASSERT(isGrowthLimitBiggerThanBaseSize()); | |
| 100 return (m_growthLimit == infinity) ? m_baseSize : m_growthLimit; | |
| 101 } | |
| 102 | |
| 103 const LayoutUnit& plannedIncrease() const { return m_plannedIncrease; } | |
| 104 | |
| 105 void growPlannedIncrease(const LayoutUnit& plannedIncrease) | |
| 106 { | |
| 107 ASSERT(plannedIncrease >= 0); | |
| 108 m_plannedIncrease += plannedIncrease; | |
| 109 } | |
| 110 | |
| 111 void updateFromPlannedIncrease(RenderGrid::AccumulatorGrowFunction trackGrow
thFunction) | |
| 112 { | |
| 113 if (m_plannedIncrease == 0) | |
| 114 return; | |
| 115 | |
| 116 (this->*trackGrowthFunction)(m_plannedIncrease); | |
| 117 m_plannedIncrease = 0; | |
| 118 } | |
| 119 | |
| 120 private: | |
| 121 bool isGrowthLimitBiggerThanBaseSize() const { return growthLimitIsInfinite(
) || m_growthLimit >= m_baseSize; } | |
| 122 | |
| 123 void ensureGrowthLimitIsBiggerThanBaseSize() | |
| 124 { | |
| 125 if (m_growthLimit != infinity && m_growthLimit < m_baseSize) | |
| 126 m_growthLimit = m_baseSize; | |
| 127 } | |
| 128 | |
| 129 LayoutUnit m_baseSize; | |
| 130 LayoutUnit m_growthLimit; | |
| 131 LayoutUnit m_plannedIncrease; | |
| 132 }; | |
| 133 | |
| 134 struct GridTrackForNormalization { | |
| 135 GridTrackForNormalization(const GridTrack& track, double flex) | |
| 136 : m_track(&track) | |
| 137 , m_flex(flex) | |
| 138 , m_normalizedFlexValue(track.baseSize() / flex) | |
| 139 { | |
| 140 } | |
| 141 | |
| 142 // Required by std::sort. | |
| 143 GridTrackForNormalization& operator=(const GridTrackForNormalization& o) | |
| 144 { | |
| 145 m_track = o.m_track; | |
| 146 m_flex = o.m_flex; | |
| 147 m_normalizedFlexValue = o.m_normalizedFlexValue; | |
| 148 return *this; | |
| 149 } | |
| 150 | |
| 151 const GridTrack* m_track; | |
| 152 double m_flex; | |
| 153 LayoutUnit m_normalizedFlexValue; | |
| 154 }; | |
| 155 | |
| 156 class RenderGrid::GridIterator { | |
| 157 WTF_MAKE_NONCOPYABLE(GridIterator); | |
| 158 public: | |
| 159 // |direction| is the direction that is fixed to |fixedTrackIndex| so e.g | |
| 160 // GridIterator(m_grid, ForColumns, 1) will walk over the rows of the 2nd co
lumn. | |
| 161 GridIterator(const GridRepresentation& grid, GridTrackSizingDirection direct
ion, size_t fixedTrackIndex, size_t varyingTrackIndex = 0) | |
| 162 : m_grid(grid) | |
| 163 , m_direction(direction) | |
| 164 , m_rowIndex((direction == ForColumns) ? varyingTrackIndex : fixedTrackI
ndex) | |
| 165 , m_columnIndex((direction == ForColumns) ? fixedTrackIndex : varyingTra
ckIndex) | |
| 166 , m_childIndex(0) | |
| 167 { | |
| 168 ASSERT(m_rowIndex < m_grid.size()); | |
| 169 ASSERT(m_columnIndex < m_grid[0].size()); | |
| 170 } | |
| 171 | |
| 172 LayoutBox* nextGridItem() | |
| 173 { | |
| 174 ASSERT(!m_grid.isEmpty()); | |
| 175 | |
| 176 size_t& varyingTrackIndex = (m_direction == ForColumns) ? m_rowIndex : m
_columnIndex; | |
| 177 const size_t endOfVaryingTrackIndex = (m_direction == ForColumns) ? m_gr
id.size() : m_grid[0].size(); | |
| 178 for (; varyingTrackIndex < endOfVaryingTrackIndex; ++varyingTrackIndex)
{ | |
| 179 const GridCell& children = m_grid[m_rowIndex][m_columnIndex]; | |
| 180 if (m_childIndex < children.size()) | |
| 181 return children[m_childIndex++]; | |
| 182 | |
| 183 m_childIndex = 0; | |
| 184 } | |
| 185 return 0; | |
| 186 } | |
| 187 | |
| 188 bool checkEmptyCells(size_t rowSpan, size_t columnSpan) const | |
| 189 { | |
| 190 // Ignore cells outside current grid as we will grow it later if needed. | |
| 191 size_t maxRows = std::min(m_rowIndex + rowSpan, m_grid.size()); | |
| 192 size_t maxColumns = std::min(m_columnIndex + columnSpan, m_grid[0].size(
)); | |
| 193 | |
| 194 // This adds a O(N^2) behavior that shouldn't be a big deal as we expect
spanning areas to be small. | |
| 195 for (size_t row = m_rowIndex; row < maxRows; ++row) { | |
| 196 for (size_t column = m_columnIndex; column < maxColumns; ++column) { | |
| 197 const GridCell& children = m_grid[row][column]; | |
| 198 if (!children.isEmpty()) | |
| 199 return false; | |
| 200 } | |
| 201 } | |
| 202 | |
| 203 return true; | |
| 204 } | |
| 205 | |
| 206 PassOwnPtr<GridCoordinate> nextEmptyGridArea(size_t fixedTrackSpan, size_t v
aryingTrackSpan) | |
| 207 { | |
| 208 ASSERT(!m_grid.isEmpty()); | |
| 209 ASSERT(fixedTrackSpan >= 1 && varyingTrackSpan >= 1); | |
| 210 | |
| 211 size_t rowSpan = (m_direction == ForColumns) ? varyingTrackSpan : fixedT
rackSpan; | |
| 212 size_t columnSpan = (m_direction == ForColumns) ? fixedTrackSpan : varyi
ngTrackSpan; | |
| 213 | |
| 214 size_t& varyingTrackIndex = (m_direction == ForColumns) ? m_rowIndex : m
_columnIndex; | |
| 215 const size_t endOfVaryingTrackIndex = (m_direction == ForColumns) ? m_gr
id.size() : m_grid[0].size(); | |
| 216 for (; varyingTrackIndex < endOfVaryingTrackIndex; ++varyingTrackIndex)
{ | |
| 217 if (checkEmptyCells(rowSpan, columnSpan)) { | |
| 218 OwnPtr<GridCoordinate> result = adoptPtr(new GridCoordinate(Grid
Span(m_rowIndex, m_rowIndex + rowSpan - 1), GridSpan(m_columnIndex, m_columnInde
x + columnSpan - 1))); | |
| 219 // Advance the iterator to avoid an infinite loop where we would
return the same grid area over and over. | |
| 220 ++varyingTrackIndex; | |
| 221 return result.release(); | |
| 222 } | |
| 223 } | |
| 224 return nullptr; | |
| 225 } | |
| 226 | |
| 227 private: | |
| 228 const GridRepresentation& m_grid; | |
| 229 GridTrackSizingDirection m_direction; | |
| 230 size_t m_rowIndex; | |
| 231 size_t m_columnIndex; | |
| 232 size_t m_childIndex; | |
| 233 }; | |
| 234 | |
| 235 struct RenderGrid::GridSizingData { | |
| 236 WTF_MAKE_NONCOPYABLE(GridSizingData); | |
| 237 STACK_ALLOCATED(); | |
| 238 public: | |
| 239 GridSizingData(size_t gridColumnCount, size_t gridRowCount) | |
| 240 : columnTracks(gridColumnCount) | |
| 241 , rowTracks(gridRowCount) | |
| 242 { | |
| 243 } | |
| 244 | |
| 245 Vector<GridTrack> columnTracks; | |
| 246 Vector<GridTrack> rowTracks; | |
| 247 Vector<size_t> contentSizedTracksIndex; | |
| 248 | |
| 249 // Performance optimization: hold onto these Vectors until the end of Layout
to avoid repeated malloc / free. | |
| 250 Vector<GridTrack*> filteredTracks; | |
| 251 Vector<GridItemWithSpan> itemsSortedByIncreasingSpan; | |
| 252 Vector<GridTrack*> growBeyondGrowthLimitsTracks; | |
| 253 }; | |
| 254 | |
| 255 RenderGrid::RenderGrid(Element* element) | |
| 256 : RenderBlock(element) | |
| 257 , m_gridIsDirty(true) | |
| 258 , m_orderIterator(this) | |
| 259 { | |
| 260 ASSERT(!childrenInline()); | |
| 261 } | |
| 262 | |
| 263 RenderGrid::~RenderGrid() | |
| 264 { | |
| 265 } | |
| 266 | |
| 267 void RenderGrid::addChild(LayoutObject* newChild, LayoutObject* beforeChild) | |
| 268 { | |
| 269 RenderBlock::addChild(newChild, beforeChild); | |
| 270 | |
| 271 if (gridIsDirty()) | |
| 272 return; | |
| 273 | |
| 274 // The grid needs to be recomputed as it might contain auto-placed items tha
t will change their position. | |
| 275 dirtyGrid(); | |
| 276 return; | |
| 277 } | |
| 278 | |
| 279 void RenderGrid::removeChild(LayoutObject* child) | |
| 280 { | |
| 281 RenderBlock::removeChild(child); | |
| 282 | |
| 283 if (gridIsDirty()) | |
| 284 return; | |
| 285 | |
| 286 // The grid needs to be recomputed as it might contain auto-placed items tha
t will change their position. | |
| 287 dirtyGrid(); | |
| 288 return; | |
| 289 } | |
| 290 | |
| 291 void RenderGrid::styleDidChange(StyleDifference diff, const LayoutStyle* oldStyl
e) | |
| 292 { | |
| 293 RenderBlock::styleDidChange(diff, oldStyle); | |
| 294 if (!oldStyle) | |
| 295 return; | |
| 296 | |
| 297 // FIXME: The following checks could be narrowed down if we kept track of wh
ich type of grid items we have: | |
| 298 // - explicit grid size changes impact negative explicitely positioned and a
uto-placed grid items. | |
| 299 // - named grid lines only impact grid items with named grid lines. | |
| 300 // - auto-flow changes only impacts auto-placed children. | |
| 301 | |
| 302 if (explicitGridDidResize(*oldStyle) | |
| 303 || namedGridLinesDefinitionDidChange(*oldStyle) | |
| 304 || oldStyle->gridAutoFlow() != styleRef().gridAutoFlow()) | |
| 305 dirtyGrid(); | |
| 306 } | |
| 307 | |
| 308 bool RenderGrid::explicitGridDidResize(const LayoutStyle& oldStyle) const | |
| 309 { | |
| 310 return oldStyle.gridTemplateColumns().size() != styleRef().gridTemplateColum
ns().size() | |
| 311 || oldStyle.gridTemplateRows().size() != styleRef().gridTemplateRows().s
ize(); | |
| 312 } | |
| 313 | |
| 314 bool RenderGrid::namedGridLinesDefinitionDidChange(const LayoutStyle& oldStyle)
const | |
| 315 { | |
| 316 return oldStyle.namedGridRowLines() != styleRef().namedGridRowLines() | |
| 317 || oldStyle.namedGridColumnLines() != styleRef().namedGridColumnLines(); | |
| 318 } | |
| 319 | |
| 320 void RenderGrid::layoutBlock(bool relayoutChildren) | |
| 321 { | |
| 322 ASSERT(needsLayout()); | |
| 323 | |
| 324 if (!relayoutChildren && simplifiedLayout()) | |
| 325 return; | |
| 326 | |
| 327 // FIXME: Much of this method is boiler plate that matches LayoutBox::layout
Block and Render*FlexibleBox::layoutBlock. | |
| 328 // It would be nice to refactor some of the duplicate code. | |
| 329 { | |
| 330 // LayoutState needs this deliberate scope to pop before updating scroll
information (which | |
| 331 // may trigger relayout). | |
| 332 LayoutState state(*this, locationOffset()); | |
| 333 | |
| 334 LayoutSize previousSize = size(); | |
| 335 | |
| 336 setLogicalHeight(0); | |
| 337 updateLogicalWidth(); | |
| 338 | |
| 339 TextAutosizer::LayoutScope textAutosizerLayoutScope(this); | |
| 340 | |
| 341 layoutGridItems(); | |
| 342 | |
| 343 LayoutUnit oldClientAfterEdge = clientLogicalBottom(); | |
| 344 updateLogicalHeight(); | |
| 345 | |
| 346 if (size() != previousSize) | |
| 347 relayoutChildren = true; | |
| 348 | |
| 349 layoutPositionedObjects(relayoutChildren || isDocumentElement()); | |
| 350 | |
| 351 computeOverflow(oldClientAfterEdge); | |
| 352 } | |
| 353 | |
| 354 updateLayerTransformAfterLayout(); | |
| 355 | |
| 356 // Update our scroll information if we're overflow:auto/scroll/hidden now th
at we know if | |
| 357 // we overflow or not. | |
| 358 if (hasOverflowClip()) | |
| 359 layer()->scrollableArea()->updateAfterLayout(); | |
| 360 | |
| 361 clearNeedsLayout(); | |
| 362 } | |
| 363 | |
| 364 void RenderGrid::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, Layo
utUnit& maxLogicalWidth) const | |
| 365 { | |
| 366 const_cast<RenderGrid*>(this)->placeItemsOnGrid(); | |
| 367 | |
| 368 GridSizingData sizingData(gridColumnCount(), gridRowCount()); | |
| 369 LayoutUnit availableLogicalSpace = 0; | |
| 370 const_cast<RenderGrid*>(this)->computeUsedBreadthOfGridTracks(ForColumns, si
zingData, availableLogicalSpace); | |
| 371 | |
| 372 for (const auto& column : sizingData.columnTracks) { | |
| 373 const LayoutUnit& minTrackBreadth = column.baseSize(); | |
| 374 const LayoutUnit& maxTrackBreadth = column.growthLimit(); | |
| 375 | |
| 376 minLogicalWidth += minTrackBreadth; | |
| 377 maxLogicalWidth += maxTrackBreadth; | |
| 378 | |
| 379 LayoutUnit scrollbarWidth = intrinsicScrollbarLogicalWidth(); | |
| 380 maxLogicalWidth += scrollbarWidth; | |
| 381 minLogicalWidth += scrollbarWidth; | |
| 382 } | |
| 383 } | |
| 384 | |
| 385 void RenderGrid::computePreferredLogicalWidths() | |
| 386 { | |
| 387 ASSERT(preferredLogicalWidthsDirty()); | |
| 388 | |
| 389 m_minPreferredLogicalWidth = 0; | |
| 390 m_maxPreferredLogicalWidth = 0; | |
| 391 | |
| 392 // FIXME: We don't take our own logical width into account. Once we do, we n
eed to make sure | |
| 393 // we apply (and test the interaction with) min-width / max-width. | |
| 394 | |
| 395 computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogi
calWidth); | |
| 396 | |
| 397 LayoutUnit borderAndPaddingInInlineDirection = borderAndPaddingLogicalWidth(
); | |
| 398 m_minPreferredLogicalWidth += borderAndPaddingInInlineDirection; | |
| 399 m_maxPreferredLogicalWidth += borderAndPaddingInInlineDirection; | |
| 400 | |
| 401 clearPreferredLogicalWidthsDirty(); | |
| 402 } | |
| 403 | |
| 404 void RenderGrid::computeUsedBreadthOfGridTracks(GridTrackSizingDirection directi
on, GridSizingData& sizingData) | |
| 405 { | |
| 406 LayoutUnit availableLogicalSpace = (direction == ForColumns) ? availableLogi
calWidth() : availableLogicalHeight(IncludeMarginBorderPadding); | |
| 407 computeUsedBreadthOfGridTracks(direction, sizingData, availableLogicalSpace)
; | |
| 408 } | |
| 409 | |
| 410 bool RenderGrid::gridElementIsShrinkToFit() | |
| 411 { | |
| 412 return isFloatingOrOutOfFlowPositioned(); | |
| 413 } | |
| 414 | |
| 415 void RenderGrid::computeUsedBreadthOfGridTracks(GridTrackSizingDirection directi
on, GridSizingData& sizingData, LayoutUnit& freeSpace) | |
| 416 { | |
| 417 const LayoutUnit initialFreeSpace = freeSpace; | |
| 418 Vector<GridTrack>& tracks = (direction == ForColumns) ? sizingData.columnTra
cks : sizingData.rowTracks; | |
| 419 Vector<size_t> flexibleSizedTracksIndex; | |
| 420 sizingData.contentSizedTracksIndex.shrink(0); | |
| 421 | |
| 422 // 1. Initialize per Grid track variables. | |
| 423 for (size_t i = 0; i < tracks.size(); ++i) { | |
| 424 GridTrack& track = tracks[i]; | |
| 425 GridTrackSize trackSize = gridTrackSize(direction, i); | |
| 426 const GridLength& minTrackBreadth = trackSize.minTrackBreadth(); | |
| 427 const GridLength& maxTrackBreadth = trackSize.maxTrackBreadth(); | |
| 428 | |
| 429 track.setBaseSize(computeUsedBreadthOfMinLength(direction, minTrackBread
th)); | |
| 430 track.setGrowthLimit(computeUsedBreadthOfMaxLength(direction, maxTrackBr
eadth, track.baseSize())); | |
| 431 | |
| 432 if (trackSize.isContentSized()) | |
| 433 sizingData.contentSizedTracksIndex.append(i); | |
| 434 if (trackSize.maxTrackBreadth().isFlex()) | |
| 435 flexibleSizedTracksIndex.append(i); | |
| 436 } | |
| 437 | |
| 438 // 2. Resolve content-based TrackSizingFunctions. | |
| 439 if (!sizingData.contentSizedTracksIndex.isEmpty()) | |
| 440 resolveContentBasedTrackSizingFunctions(direction, sizingData, freeSpace
); | |
| 441 | |
| 442 for (const auto& track: tracks) { | |
| 443 ASSERT(!track.growthLimitIsInfinite()); | |
| 444 freeSpace -= track.baseSize(); | |
| 445 } | |
| 446 | |
| 447 const bool hasUndefinedRemainingSpace = (direction == ForRows) ? style()->lo
gicalHeight().isAuto() : gridElementIsShrinkToFit(); | |
| 448 | |
| 449 if (!hasUndefinedRemainingSpace && freeSpace <= 0) | |
| 450 return; | |
| 451 | |
| 452 // 3. Grow all Grid tracks in GridTracks from their baseSize up to their gro
wthLimit value until freeSpace is exhausted. | |
| 453 const size_t tracksSize = tracks.size(); | |
| 454 if (!hasUndefinedRemainingSpace) { | |
| 455 Vector<GridTrack*> tracksForDistribution(tracksSize); | |
| 456 for (size_t i = 0; i < tracksSize; ++i) | |
| 457 tracksForDistribution[i] = tracks.data() + i; | |
| 458 | |
| 459 distributeSpaceToTracks(tracksForDistribution, nullptr, &GridTrack::base
Size, &GridTrack::growBaseSize, sizingData, freeSpace); | |
| 460 } else { | |
| 461 for (auto& track : tracks) | |
| 462 track.setBaseSize(track.growthLimit()); | |
| 463 } | |
| 464 | |
| 465 if (flexibleSizedTracksIndex.isEmpty()) | |
| 466 return; | |
| 467 | |
| 468 // 4. Grow all Grid tracks having a fraction as the MaxTrackSizingFunction. | |
| 469 double normalizedFractionBreadth = 0; | |
| 470 if (!hasUndefinedRemainingSpace) { | |
| 471 normalizedFractionBreadth = computeNormalizedFractionBreadth(tracks, Gri
dSpan(0, tracks.size() - 1), direction, initialFreeSpace); | |
| 472 } else { | |
| 473 for (const auto& trackIndex : flexibleSizedTracksIndex) { | |
| 474 GridTrackSize trackSize = gridTrackSize(direction, trackIndex); | |
| 475 normalizedFractionBreadth = std::max(normalizedFractionBreadth, trac
ks[trackIndex].baseSize() / trackSize.maxTrackBreadth().flex()); | |
| 476 } | |
| 477 | |
| 478 for (size_t i = 0; i < flexibleSizedTracksIndex.size(); ++i) { | |
| 479 GridIterator iterator(m_grid, direction, flexibleSizedTracksIndex[i]
); | |
| 480 while (LayoutBox* gridItem = iterator.nextGridItem()) { | |
| 481 const GridCoordinate coordinate = cachedGridCoordinate(*gridItem
); | |
| 482 const GridSpan span = (direction == ForColumns) ? coordinate.col
umns : coordinate.rows; | |
| 483 | |
| 484 // Do not include already processed items. | |
| 485 if (i > 0 && span.resolvedInitialPosition.toInt() <= flexibleSiz
edTracksIndex[i - 1]) | |
| 486 continue; | |
| 487 | |
| 488 double itemNormalizedFlexBreadth = computeNormalizedFractionBrea
dth(tracks, span, direction, maxContentForChild(*gridItem, direction, sizingData
.columnTracks)); | |
| 489 normalizedFractionBreadth = std::max(normalizedFractionBreadth,
itemNormalizedFlexBreadth); | |
| 490 } | |
| 491 } | |
| 492 } | |
| 493 | |
| 494 for (const auto& trackIndex : flexibleSizedTracksIndex) { | |
| 495 GridTrackSize trackSize = gridTrackSize(direction, trackIndex); | |
| 496 | |
| 497 LayoutUnit baseSize = std::max<LayoutUnit>(tracks[trackIndex].baseSize()
, normalizedFractionBreadth * trackSize.maxTrackBreadth().flex()); | |
| 498 tracks[trackIndex].setBaseSize(baseSize); | |
| 499 freeSpace -= baseSize; | |
| 500 } | |
| 501 | |
| 502 // FIXME: Should ASSERT flexible tracks exhaust the freeSpace ? (see issue 7
39613002). | |
| 503 } | |
| 504 | |
| 505 LayoutUnit RenderGrid::computeUsedBreadthOfMinLength(GridTrackSizingDirection di
rection, const GridLength& gridLength) const | |
| 506 { | |
| 507 if (gridLength.isFlex()) | |
| 508 return 0; | |
| 509 | |
| 510 const Length& trackLength = gridLength.length(); | |
| 511 ASSERT(!trackLength.isAuto()); | |
| 512 if (trackLength.isSpecified()) | |
| 513 return computeUsedBreadthOfSpecifiedLength(direction, trackLength); | |
| 514 | |
| 515 ASSERT(trackLength.isMinContent() || trackLength.isMaxContent()); | |
| 516 return 0; | |
| 517 } | |
| 518 | |
| 519 LayoutUnit RenderGrid::computeUsedBreadthOfMaxLength(GridTrackSizingDirection di
rection, const GridLength& gridLength, LayoutUnit usedBreadth) const | |
| 520 { | |
| 521 if (gridLength.isFlex()) | |
| 522 return usedBreadth; | |
| 523 | |
| 524 const Length& trackLength = gridLength.length(); | |
| 525 ASSERT(!trackLength.isAuto()); | |
| 526 if (trackLength.isSpecified()) { | |
| 527 LayoutUnit computedBreadth = computeUsedBreadthOfSpecifiedLength(directi
on, trackLength); | |
| 528 ASSERT(computedBreadth != infinity); | |
| 529 return computedBreadth; | |
| 530 } | |
| 531 | |
| 532 ASSERT(trackLength.isMinContent() || trackLength.isMaxContent()); | |
| 533 return infinity; | |
| 534 } | |
| 535 | |
| 536 LayoutUnit RenderGrid::computeUsedBreadthOfSpecifiedLength(GridTrackSizingDirect
ion direction, const Length& trackLength) const | |
| 537 { | |
| 538 ASSERT(trackLength.isSpecified()); | |
| 539 // FIXME: The -1 here should be replaced by whatever the intrinsic height of
the grid is. | |
| 540 return valueForLength(trackLength, direction == ForColumns ? logicalWidth()
: computeContentLogicalHeight(style()->logicalHeight(), -1)); | |
| 541 } | |
| 542 | |
| 543 static bool sortByGridNormalizedFlexValue(const GridTrackForNormalization& track
1, const GridTrackForNormalization& track2) | |
| 544 { | |
| 545 return track1.m_normalizedFlexValue < track2.m_normalizedFlexValue; | |
| 546 } | |
| 547 | |
| 548 double RenderGrid::computeNormalizedFractionBreadth(Vector<GridTrack>& tracks, c
onst GridSpan& tracksSpan, GridTrackSizingDirection direction, LayoutUnit spaceT
oFill) const | |
| 549 { | |
| 550 LayoutUnit allocatedSpace; | |
| 551 Vector<GridTrackForNormalization> tracksForNormalization; | |
| 552 for (const auto& resolvedPosition : tracksSpan) { | |
| 553 GridTrack& track = tracks[resolvedPosition.toInt()]; | |
| 554 allocatedSpace += track.baseSize(); | |
| 555 | |
| 556 GridTrackSize trackSize = gridTrackSize(direction, resolvedPosition.toIn
t()); | |
| 557 if (!trackSize.maxTrackBreadth().isFlex()) | |
| 558 continue; | |
| 559 | |
| 560 tracksForNormalization.append(GridTrackForNormalization(track, trackSize
.maxTrackBreadth().flex())); | |
| 561 } | |
| 562 | |
| 563 // The function is not called if we don't have <flex> grid tracks | |
| 564 ASSERT(!tracksForNormalization.isEmpty()); | |
| 565 | |
| 566 std::sort(tracksForNormalization.begin(), tracksForNormalization.end(), sort
ByGridNormalizedFlexValue); | |
| 567 | |
| 568 // These values work together: as we walk over our grid tracks, we increase
fractionValueBasedOnGridItemsRatio | |
| 569 // to match a grid track's usedBreadth to <flex> ratio until the total fract
ions sized grid tracks wouldn't | |
| 570 // fit into availableLogicalSpaceIgnoringFractionTracks. | |
| 571 double accumulatedFractions = 0; | |
| 572 LayoutUnit fractionValueBasedOnGridItemsRatio = 0; | |
| 573 LayoutUnit availableLogicalSpaceIgnoringFractionTracks = spaceToFill - alloc
atedSpace; | |
| 574 | |
| 575 for (const auto& track : tracksForNormalization) { | |
| 576 if (track.m_normalizedFlexValue > fractionValueBasedOnGridItemsRatio) { | |
| 577 // If the normalized flex value (we ordered |tracksForNormalization|
by increasing normalized flex value) | |
| 578 // will make us overflow our container, then stop. We have the previ
ous step's ratio is the best fit. | |
| 579 if (track.m_normalizedFlexValue * accumulatedFractions > availableLo
gicalSpaceIgnoringFractionTracks) | |
| 580 break; | |
| 581 | |
| 582 fractionValueBasedOnGridItemsRatio = track.m_normalizedFlexValue; | |
| 583 } | |
| 584 | |
| 585 accumulatedFractions += track.m_flex; | |
| 586 // This item was processed so we re-add its used breadth to the availabl
e space to accurately count the remaining space. | |
| 587 availableLogicalSpaceIgnoringFractionTracks += track.m_track->baseSize()
; | |
| 588 } | |
| 589 | |
| 590 return availableLogicalSpaceIgnoringFractionTracks / accumulatedFractions; | |
| 591 } | |
| 592 | |
| 593 bool RenderGrid::hasDefiniteLogicalSize(GridTrackSizingDirection direction) cons
t | |
| 594 { | |
| 595 return (direction == ForRows) ? hasDefiniteLogicalHeight() : hasDefiniteLogi
calWidth(); | |
| 596 } | |
| 597 | |
| 598 GridTrackSize RenderGrid::gridTrackSize(GridTrackSizingDirection direction, size
_t i) const | |
| 599 { | |
| 600 bool isForColumns = direction == ForColumns; | |
| 601 const Vector<GridTrackSize>& trackStyles = isForColumns ? style()->gridTempl
ateColumns() : style()->gridTemplateRows(); | |
| 602 const GridTrackSize& trackSize = (i >= trackStyles.size()) ? (isForColumns ?
style()->gridAutoColumns() : style()->gridAutoRows()) : trackStyles[i]; | |
| 603 | |
| 604 // If the logical width/height of the grid container is indefinite, percenta
ge values are treated as <auto> (or in | |
| 605 // the case of minmax() as min-content for the first position and max-conten
t for the second). | |
| 606 if (!hasDefiniteLogicalSize(direction)) { | |
| 607 const GridLength& oldMinTrackBreadth = trackSize.minTrackBreadth(); | |
| 608 const GridLength& oldMaxTrackBreadth = trackSize.maxTrackBreadth(); | |
| 609 return GridTrackSize(oldMinTrackBreadth.isPercentage() ? Length(MinConte
nt) : oldMinTrackBreadth, oldMaxTrackBreadth.isPercentage() ? Length(MaxContent)
: oldMaxTrackBreadth); | |
| 610 } | |
| 611 | |
| 612 return trackSize; | |
| 613 } | |
| 614 | |
| 615 LayoutUnit RenderGrid::logicalHeightForChild(LayoutBox& child, Vector<GridTrack>
& columnTracks) | |
| 616 { | |
| 617 SubtreeLayoutScope layoutScope(child); | |
| 618 LayoutUnit oldOverrideContainingBlockContentLogicalWidth = child.hasOverride
ContainingBlockLogicalWidth() ? child.overrideContainingBlockContentLogicalWidth
() : LayoutUnit(); | |
| 619 LayoutUnit overrideContainingBlockContentLogicalWidth = gridAreaBreadthForCh
ild(child, ForColumns, columnTracks); | |
| 620 if (child.style()->logicalHeight().isPercent() || oldOverrideContainingBlock
ContentLogicalWidth != overrideContainingBlockContentLogicalWidth) | |
| 621 layoutScope.setNeedsLayout(&child); | |
| 622 | |
| 623 child.clearOverrideLogicalContentHeight(); | |
| 624 | |
| 625 child.setOverrideContainingBlockContentLogicalWidth(overrideContainingBlockC
ontentLogicalWidth); | |
| 626 // If |child| has a percentage logical height, we shouldn't let it override
its intrinsic height, which is | |
| 627 // what we are interested in here. Thus we need to set the override logical
height to -1 (no possible resolution). | |
| 628 child.setOverrideContainingBlockContentLogicalHeight(-1); | |
| 629 child.layoutIfNeeded(); | |
| 630 return child.logicalHeight() + child.marginLogicalHeight(); | |
| 631 } | |
| 632 | |
| 633 LayoutUnit RenderGrid::minContentForChild(LayoutBox& child, GridTrackSizingDirec
tion direction, Vector<GridTrack>& columnTracks) | |
| 634 { | |
| 635 bool hasOrthogonalWritingMode = child.isHorizontalWritingMode() != isHorizon
talWritingMode(); | |
| 636 // FIXME: Properly support orthogonal writing mode. | |
| 637 if (hasOrthogonalWritingMode) | |
| 638 return 0; | |
| 639 | |
| 640 if (direction == ForColumns) { | |
| 641 // FIXME: It's unclear if we should return the intrinsic width or the pr
eferred width. | |
| 642 // See http://lists.w3.org/Archives/Public/www-style/2013Jan/0245.html | |
| 643 return child.minPreferredLogicalWidth() + marginIntrinsicLogicalWidthFor
Child(child); | |
| 644 } | |
| 645 | |
| 646 return logicalHeightForChild(child, columnTracks); | |
| 647 } | |
| 648 | |
| 649 LayoutUnit RenderGrid::maxContentForChild(LayoutBox& child, GridTrackSizingDirec
tion direction, Vector<GridTrack>& columnTracks) | |
| 650 { | |
| 651 bool hasOrthogonalWritingMode = child.isHorizontalWritingMode() != isHorizon
talWritingMode(); | |
| 652 // FIXME: Properly support orthogonal writing mode. | |
| 653 if (hasOrthogonalWritingMode) | |
| 654 return LayoutUnit(); | |
| 655 | |
| 656 if (direction == ForColumns) { | |
| 657 // FIXME: It's unclear if we should return the intrinsic width or the pr
eferred width. | |
| 658 // See http://lists.w3.org/Archives/Public/www-style/2013Jan/0245.html | |
| 659 return child.maxPreferredLogicalWidth() + marginIntrinsicLogicalWidthFor
Child(child); | |
| 660 } | |
| 661 | |
| 662 return logicalHeightForChild(child, columnTracks); | |
| 663 } | |
| 664 | |
| 665 // We're basically using a class instead of a std::pair for two reasons. First o
f all, accessing gridItem() or | |
| 666 // coordinate() is much more self-explanatory that using .first or .second membe
rs in the pair. Secondly the class | |
| 667 // allows us to precompute the value of the span, something which is quite conve
nient for the sorting. Having a | |
| 668 // std::pair<LayoutBox*, size_t> does not work either because we still need the
GridCoordinate so we'd have to add an | |
| 669 // extra hash lookup for each item at the beginning of RenderGrid::resolveConten
tBasedTrackSizingFunctionsForItems(). | |
| 670 class GridItemWithSpan { | |
| 671 public: | |
| 672 GridItemWithSpan(LayoutBox& gridItem, const GridCoordinate& coordinate, Grid
TrackSizingDirection direction) | |
| 673 : m_gridItem(&gridItem) | |
| 674 , m_coordinate(coordinate) | |
| 675 { | |
| 676 const GridSpan& span = (direction == ForRows) ? coordinate.rows : coordi
nate.columns; | |
| 677 m_span = span.resolvedFinalPosition.toInt() - span.resolvedInitialPositi
on.toInt() + 1; | |
| 678 } | |
| 679 | |
| 680 LayoutBox& gridItem() const { return *m_gridItem; } | |
| 681 GridCoordinate coordinate() const { return m_coordinate; } | |
| 682 #if ENABLE(ASSERT) | |
| 683 size_t span() const { return m_span; } | |
| 684 #endif | |
| 685 | |
| 686 bool operator<(const GridItemWithSpan other) const { return m_span < other.m
_span; } | |
| 687 | |
| 688 private: | |
| 689 LayoutBox* m_gridItem; | |
| 690 GridCoordinate m_coordinate; | |
| 691 size_t m_span; | |
| 692 }; | |
| 693 | |
| 694 bool RenderGrid::spanningItemCrossesFlexibleSizedTracks(const GridCoordinate& co
ordinate, GridTrackSizingDirection direction) const | |
| 695 { | |
| 696 const GridResolvedPosition initialTrackPosition = (direction == ForColumns)
? coordinate.columns.resolvedInitialPosition : coordinate.rows.resolvedInitialPo
sition; | |
| 697 const GridResolvedPosition finalTrackPosition = (direction == ForColumns) ?
coordinate.columns.resolvedFinalPosition : coordinate.rows.resolvedFinalPosition
; | |
| 698 | |
| 699 for (GridResolvedPosition trackPosition = initialTrackPosition; trackPositio
n <= finalTrackPosition; ++trackPosition) { | |
| 700 const GridTrackSize& trackSize = gridTrackSize(direction, trackPosition.
toInt()); | |
| 701 if (trackSize.minTrackBreadth().isFlex() || trackSize.maxTrackBreadth().
isFlex()) | |
| 702 return true; | |
| 703 } | |
| 704 | |
| 705 return false; | |
| 706 } | |
| 707 | |
| 708 static inline size_t integerSpanForDirection(const GridCoordinate& coordinate, G
ridTrackSizingDirection direction) | |
| 709 { | |
| 710 return (direction == ForRows) ? coordinate.rows.integerSpan() : coordinate.c
olumns.integerSpan(); | |
| 711 } | |
| 712 | |
| 713 void RenderGrid::resolveContentBasedTrackSizingFunctions(GridTrackSizingDirectio
n direction, GridSizingData& sizingData, LayoutUnit& availableLogicalSpace) | |
| 714 { | |
| 715 sizingData.itemsSortedByIncreasingSpan.shrink(0); | |
| 716 HashSet<LayoutBox*> itemsSet; | |
| 717 for (const auto& trackIndex : sizingData.contentSizedTracksIndex) { | |
| 718 GridIterator iterator(m_grid, direction, trackIndex); | |
| 719 GridTrack& track = (direction == ForColumns) ? sizingData.columnTracks[t
rackIndex] : sizingData.rowTracks[trackIndex]; | |
| 720 while (LayoutBox* gridItem = iterator.nextGridItem()) { | |
| 721 if (itemsSet.add(gridItem).isNewEntry) { | |
| 722 const GridCoordinate& coordinate = cachedGridCoordinate(*gridIte
m); | |
| 723 if (integerSpanForDirection(coordinate, direction) == 1) { | |
| 724 resolveContentBasedTrackSizingFunctionsForNonSpanningItems(d
irection, coordinate, *gridItem, track, sizingData.columnTracks); | |
| 725 } else if (!spanningItemCrossesFlexibleSizedTracks(coordinate, d
irection)) { | |
| 726 sizingData.itemsSortedByIncreasingSpan.append(GridItemWithSp
an(*gridItem, coordinate, direction)); | |
| 727 } | |
| 728 } | |
| 729 } | |
| 730 } | |
| 731 std::sort(sizingData.itemsSortedByIncreasingSpan.begin(), sizingData.itemsSo
rtedByIncreasingSpan.end()); | |
| 732 | |
| 733 Vector<GridItemWithSpan>::iterator end = sizingData.itemsSortedByIncreasingS
pan.end(); | |
| 734 for (Vector<GridItemWithSpan>::iterator it = sizingData.itemsSortedByIncreas
ingSpan.begin(); it != end; ++it) { | |
| 735 GridItemWithSpan itemWithSpan = *it; | |
| 736 resolveContentBasedTrackSizingFunctionsForItems(direction, sizingData, i
temWithSpan, &GridTrackSize::hasMinOrMaxContentMinTrackBreadth, &RenderGrid::min
ContentForChild, &GridTrack::baseSize, &GridTrack::growBaseSize, &GridTrackSize:
:hasMinContentMinTrackBreadthAndMinOrMaxContentMaxTrackBreadth); | |
| 737 resolveContentBasedTrackSizingFunctionsForItems(direction, sizingData, i
temWithSpan, &GridTrackSize::hasMaxContentMinTrackBreadth, &RenderGrid::maxConte
ntForChild, &GridTrack::baseSize, &GridTrack::growBaseSize, &GridTrackSize::hasM
axContentMinTrackBreadthAndMaxContentMaxTrackBreadth); | |
| 738 resolveContentBasedTrackSizingFunctionsForItems(direction, sizingData, i
temWithSpan, &GridTrackSize::hasMinOrMaxContentMaxTrackBreadth, &RenderGrid::min
ContentForChild, &GridTrack::growthLimitIfNotInfinite, &GridTrack::growGrowthLim
it); | |
| 739 resolveContentBasedTrackSizingFunctionsForItems(direction, sizingData, i
temWithSpan, &GridTrackSize::hasMaxContentMaxTrackBreadth, &RenderGrid::maxConte
ntForChild, &GridTrack::growthLimitIfNotInfinite, &GridTrack::growGrowthLimit); | |
| 740 } | |
| 741 | |
| 742 for (const auto& trackIndex : sizingData.contentSizedTracksIndex) { | |
| 743 GridTrack& track = (direction == ForColumns) ? sizingData.columnTracks[t
rackIndex] : sizingData.rowTracks[trackIndex]; | |
| 744 if (track.growthLimitIsInfinite()) | |
| 745 track.setGrowthLimit(track.baseSize()); | |
| 746 } | |
| 747 } | |
| 748 | |
| 749 void RenderGrid::resolveContentBasedTrackSizingFunctionsForNonSpanningItems(Grid
TrackSizingDirection direction, const GridCoordinate& coordinate, LayoutBox& gri
dItem, GridTrack& track, Vector<GridTrack>& columnTracks) | |
| 750 { | |
| 751 const GridResolvedPosition trackPosition = (direction == ForColumns) ? coord
inate.columns.resolvedInitialPosition : coordinate.rows.resolvedInitialPosition; | |
| 752 GridTrackSize trackSize = gridTrackSize(direction, trackPosition.toInt()); | |
| 753 | |
| 754 if (trackSize.hasMinContentMinTrackBreadth()) | |
| 755 track.setBaseSize(std::max(track.baseSize(), minContentForChild(gridItem
, direction, columnTracks))); | |
| 756 else if (trackSize.hasMaxContentMinTrackBreadth()) | |
| 757 track.setBaseSize(std::max(track.baseSize(), maxContentForChild(gridItem
, direction, columnTracks))); | |
| 758 | |
| 759 if (trackSize.hasMinContentMaxTrackBreadth()) | |
| 760 track.setGrowthLimit(std::max(track.growthLimit(), minContentForChild(gr
idItem, direction, columnTracks))); | |
| 761 else if (trackSize.hasMaxContentMaxTrackBreadth()) | |
| 762 track.setGrowthLimit(std::max(track.growthLimit(), maxContentForChild(gr
idItem, direction, columnTracks))); | |
| 763 } | |
| 764 | |
| 765 void RenderGrid::resolveContentBasedTrackSizingFunctionsForItems(GridTrackSizing
Direction direction, GridSizingData& sizingData, GridItemWithSpan& gridItemWithS
pan, FilterFunction filterFunction, SizingFunction sizingFunction, AccumulatorGe
tter trackGetter, AccumulatorGrowFunction trackGrowthFunction, FilterFunction gr
owAboveMaxBreadthFilterFunction) | |
| 766 { | |
| 767 ASSERT(gridItemWithSpan.span() > 1); | |
| 768 const GridCoordinate coordinate = gridItemWithSpan.coordinate(); | |
| 769 const GridSpan& itemSpan = (direction == ForColumns) ? coordinate.columns :
coordinate.rows; | |
| 770 | |
| 771 sizingData.growBeyondGrowthLimitsTracks.shrink(0); | |
| 772 sizingData.filteredTracks.shrink(0); | |
| 773 LayoutUnit spanningTracksSize; | |
| 774 for (const auto& trackPosition : itemSpan) { | |
| 775 GridTrackSize trackSize = gridTrackSize(direction, trackPosition.toInt()
); | |
| 776 GridTrack& track = (direction == ForColumns) ? sizingData.columnTracks[t
rackPosition.toInt()] : sizingData.rowTracks[trackPosition.toInt()]; | |
| 777 spanningTracksSize += (track.*trackGetter)(); | |
| 778 if (!(trackSize.*filterFunction)()) | |
| 779 continue; | |
| 780 | |
| 781 sizingData.filteredTracks.append(&track); | |
| 782 | |
| 783 if (!growAboveMaxBreadthFilterFunction || (trackSize.*growAboveMaxBreadt
hFilterFunction)()) | |
| 784 sizingData.growBeyondGrowthLimitsTracks.append(&track); | |
| 785 } | |
| 786 | |
| 787 if (sizingData.filteredTracks.isEmpty()) | |
| 788 return; | |
| 789 | |
| 790 // Specs mandate to floor extraSpace to 0. Instead we directly avoid the fun
ction call in those cases as it will be | |
| 791 // a noop in terms of track sizing. | |
| 792 LayoutUnit extraSpace = (this->*sizingFunction)(gridItemWithSpan.gridItem(),
direction, sizingData.columnTracks) - spanningTracksSize; | |
| 793 if (extraSpace > 0) { | |
| 794 Vector<GridTrack*>* tracksToGrowBeyondGrowthLimits = sizingData.growBeyo
ndGrowthLimitsTracks.isEmpty() ? &sizingData.filteredTracks : &sizingData.growBe
yondGrowthLimitsTracks; | |
| 795 distributeSpaceToTracks(sizingData.filteredTracks, tracksToGrowBeyondGro
wthLimits, trackGetter, trackGrowthFunction, sizingData, extraSpace); | |
| 796 } | |
| 797 } | |
| 798 | |
| 799 static bool sortByGridTrackGrowthPotential(const GridTrack* track1, const GridTr
ack* track2) | |
| 800 { | |
| 801 // This check ensures that we respect the irreflexivity property of the stri
ct weak ordering required by std::sort | |
| 802 // (forall x: NOT x < x). | |
| 803 if (track1->growthLimitIsInfinite() && track2->growthLimitIsInfinite()) | |
| 804 return false; | |
| 805 | |
| 806 if (track1->growthLimitIsInfinite() || track2->growthLimitIsInfinite()) | |
| 807 return track2->growthLimitIsInfinite(); | |
| 808 | |
| 809 return (track1->growthLimit() - track1->baseSize()) < (track2->growthLimit()
- track2->baseSize()); | |
| 810 } | |
| 811 | |
| 812 void RenderGrid::distributeSpaceToTracks(Vector<GridTrack*>& tracks, const Vecto
r<GridTrack*>* growBeyondGrowthLimitsTracks, AccumulatorGetter trackGetter, Accu
mulatorGrowFunction trackGrowthFunction, GridSizingData& sizingData, LayoutUnit&
availableLogicalSpace) | |
| 813 { | |
| 814 ASSERT(availableLogicalSpace > 0); | |
| 815 std::sort(tracks.begin(), tracks.end(), sortByGridTrackGrowthPotential); | |
| 816 | |
| 817 size_t tracksSize = tracks.size(); | |
| 818 for (size_t i = 0; i < tracksSize; ++i) { | |
| 819 GridTrack& track = *tracks[i]; | |
| 820 ASSERT(track.plannedIncrease() == 0); | |
| 821 LayoutUnit availableLogicalSpaceShare = availableLogicalSpace / (tracksS
ize - i); | |
| 822 const LayoutUnit& trackBreadth = (track.*trackGetter)(); | |
| 823 LayoutUnit growthShare = track.growthLimitIsInfinite() ? availableLogica
lSpaceShare : std::min(availableLogicalSpaceShare, track.growthLimit() - trackBr
eadth); | |
| 824 // We should never shrink any grid track or else we can't guarantee we a
bide by our min-sizing function. | |
| 825 if (growthShare > 0) { | |
| 826 track.growPlannedIncrease(growthShare); | |
| 827 availableLogicalSpace -= growthShare; | |
| 828 } | |
| 829 } | |
| 830 | |
| 831 if (availableLogicalSpace > 0 && growBeyondGrowthLimitsTracks) { | |
| 832 size_t tracksGrowingAboveMaxBreadthSize = growBeyondGrowthLimitsTracks->
size(); | |
| 833 for (size_t i = 0; i < tracksGrowingAboveMaxBreadthSize; ++i) { | |
| 834 GridTrack* track = growBeyondGrowthLimitsTracks->at(i); | |
| 835 LayoutUnit growthShare = availableLogicalSpace / (tracksGrowingAbove
MaxBreadthSize - i); | |
| 836 track->growPlannedIncrease(growthShare); | |
| 837 availableLogicalSpace -= growthShare; | |
| 838 } | |
| 839 } | |
| 840 | |
| 841 for (auto* track: tracks) { | |
| 842 track->updateFromPlannedIncrease(trackGrowthFunction); | |
| 843 ASSERT(track->plannedIncrease() == 0); | |
| 844 } | |
| 845 } | |
| 846 | |
| 847 #if ENABLE(ASSERT) | |
| 848 bool RenderGrid::tracksAreWiderThanMinTrackBreadth(GridTrackSizingDirection dire
ction, const Vector<GridTrack>& tracks) | |
| 849 { | |
| 850 for (size_t i = 0; i < tracks.size(); ++i) { | |
| 851 GridTrackSize trackSize = gridTrackSize(direction, i); | |
| 852 const GridLength& minTrackBreadth = trackSize.minTrackBreadth(); | |
| 853 if (computeUsedBreadthOfMinLength(direction, minTrackBreadth) > tracks[i
].baseSize()) | |
| 854 return false; | |
| 855 } | |
| 856 return true; | |
| 857 } | |
| 858 #endif | |
| 859 | |
| 860 void RenderGrid::ensureGridSize(size_t maximumRowIndex, size_t maximumColumnInde
x) | |
| 861 { | |
| 862 const size_t oldRowSize = gridRowCount(); | |
| 863 if (maximumRowIndex >= oldRowSize) { | |
| 864 m_grid.grow(maximumRowIndex + 1); | |
| 865 for (size_t row = oldRowSize; row < gridRowCount(); ++row) | |
| 866 m_grid[row].grow(gridColumnCount()); | |
| 867 } | |
| 868 | |
| 869 if (maximumColumnIndex >= gridColumnCount()) { | |
| 870 for (size_t row = 0; row < gridRowCount(); ++row) | |
| 871 m_grid[row].grow(maximumColumnIndex + 1); | |
| 872 } | |
| 873 } | |
| 874 | |
| 875 void RenderGrid::insertItemIntoGrid(LayoutBox& child, const GridCoordinate& coor
dinate) | |
| 876 { | |
| 877 ensureGridSize(coordinate.rows.resolvedFinalPosition.toInt(), coordinate.col
umns.resolvedFinalPosition.toInt()); | |
| 878 | |
| 879 for (GridSpan::iterator row = coordinate.rows.begin(); row != coordinate.row
s.end(); ++row) { | |
| 880 for (GridSpan::iterator column = coordinate.columns.begin(); column != c
oordinate.columns.end(); ++column) | |
| 881 m_grid[row.toInt()][column.toInt()].append(&child); | |
| 882 } | |
| 883 | |
| 884 RELEASE_ASSERT(!m_gridItemCoordinate.contains(&child)); | |
| 885 m_gridItemCoordinate.set(&child, coordinate); | |
| 886 } | |
| 887 | |
| 888 void RenderGrid::placeItemsOnGrid() | |
| 889 { | |
| 890 if (!gridIsDirty()) | |
| 891 return; | |
| 892 | |
| 893 ASSERT(m_gridItemCoordinate.isEmpty()); | |
| 894 | |
| 895 populateExplicitGridAndOrderIterator(); | |
| 896 | |
| 897 // We clear the dirty bit here as the grid sizes have been updated, this mea
ns | |
| 898 // that we can safely call gridRowCount() / gridColumnCount(). | |
| 899 m_gridIsDirty = false; | |
| 900 | |
| 901 Vector<LayoutBox*> autoMajorAxisAutoGridItems; | |
| 902 Vector<LayoutBox*> specifiedMajorAxisAutoGridItems; | |
| 903 for (LayoutBox* child = m_orderIterator.first(); child; child = m_orderItera
tor.next()) { | |
| 904 if (child->isOutOfFlowPositioned()) | |
| 905 continue; | |
| 906 | |
| 907 OwnPtr<GridSpan> rowPositions = GridResolvedPosition::resolveGridPositio
nsFromStyle(*style(), *child, ForRows); | |
| 908 OwnPtr<GridSpan> columnPositions = GridResolvedPosition::resolveGridPosi
tionsFromStyle(*style(), *child, ForColumns); | |
| 909 if (!rowPositions || !columnPositions) { | |
| 910 GridSpan* majorAxisPositions = (autoPlacementMajorAxisDirection() ==
ForColumns) ? columnPositions.get() : rowPositions.get(); | |
| 911 if (!majorAxisPositions) | |
| 912 autoMajorAxisAutoGridItems.append(child); | |
| 913 else | |
| 914 specifiedMajorAxisAutoGridItems.append(child); | |
| 915 continue; | |
| 916 } | |
| 917 insertItemIntoGrid(*child, GridCoordinate(*rowPositions, *columnPosition
s)); | |
| 918 } | |
| 919 | |
| 920 ASSERT(gridRowCount() >= GridResolvedPosition::explicitGridRowCount(*style()
)); | |
| 921 ASSERT(gridColumnCount() >= GridResolvedPosition::explicitGridColumnCount(*s
tyle())); | |
| 922 | |
| 923 placeSpecifiedMajorAxisItemsOnGrid(specifiedMajorAxisAutoGridItems); | |
| 924 placeAutoMajorAxisItemsOnGrid(autoMajorAxisAutoGridItems); | |
| 925 | |
| 926 m_grid.shrinkToFit(); | |
| 927 } | |
| 928 | |
| 929 void RenderGrid::populateExplicitGridAndOrderIterator() | |
| 930 { | |
| 931 OrderIteratorPopulator populator(m_orderIterator); | |
| 932 | |
| 933 size_t maximumRowIndex = std::max<size_t>(1, GridResolvedPosition::explicitG
ridRowCount(*style())); | |
| 934 size_t maximumColumnIndex = std::max<size_t>(1, GridResolvedPosition::explic
itGridColumnCount(*style())); | |
| 935 | |
| 936 ASSERT(m_gridItemsIndexesMap.isEmpty()); | |
| 937 size_t childIndex = 0; | |
| 938 for (LayoutBox* child = firstChildBox(); child; child = child->nextInFlowSib
lingBox()) { | |
| 939 populator.collectChild(child); | |
| 940 m_gridItemsIndexesMap.set(child, childIndex++); | |
| 941 | |
| 942 // This function bypasses the cache (cachedGridCoordinate()) as it is us
ed to build it. | |
| 943 OwnPtr<GridSpan> rowPositions = GridResolvedPosition::resolveGridPositio
nsFromStyle(*style(), *child, ForRows); | |
| 944 OwnPtr<GridSpan> columnPositions = GridResolvedPosition::resolveGridPosi
tionsFromStyle(*style(), *child, ForColumns); | |
| 945 | |
| 946 // |positions| is 0 if we need to run the auto-placement algorithm. | |
| 947 if (rowPositions) { | |
| 948 maximumRowIndex = std::max<size_t>(maximumRowIndex, rowPositions->re
solvedFinalPosition.next().toInt()); | |
| 949 } else { | |
| 950 // Grow the grid for items with a definite row span, getting the lar
gest such span. | |
| 951 GridSpan positions = GridResolvedPosition::resolveGridPositionsFromA
utoPlacementPosition(*style(), *child, ForRows, GridResolvedPosition(0)); | |
| 952 maximumRowIndex = std::max<size_t>(maximumRowIndex, positions.resolv
edFinalPosition.next().toInt()); | |
| 953 } | |
| 954 | |
| 955 if (columnPositions) { | |
| 956 maximumColumnIndex = std::max<size_t>(maximumColumnIndex, columnPosi
tions->resolvedFinalPosition.next().toInt()); | |
| 957 } else { | |
| 958 // Grow the grid for items with a definite column span, getting the
largest such span. | |
| 959 GridSpan positions = GridResolvedPosition::resolveGridPositionsFromA
utoPlacementPosition(*style(), *child, ForColumns, GridResolvedPosition(0)); | |
| 960 maximumColumnIndex = std::max<size_t>(maximumColumnIndex, positions.
resolvedFinalPosition.next().toInt()); | |
| 961 } | |
| 962 } | |
| 963 | |
| 964 m_grid.grow(maximumRowIndex); | |
| 965 for (auto& column : m_grid) | |
| 966 column.grow(maximumColumnIndex); | |
| 967 } | |
| 968 | |
| 969 PassOwnPtr<GridCoordinate> RenderGrid::createEmptyGridAreaAtSpecifiedPositionsOu
tsideGrid(const LayoutBox& gridItem, GridTrackSizingDirection specifiedDirection
, const GridSpan& specifiedPositions) const | |
| 970 { | |
| 971 GridTrackSizingDirection crossDirection = specifiedDirection == ForColumns ?
ForRows : ForColumns; | |
| 972 const size_t endOfCrossDirection = crossDirection == ForColumns ? gridColumn
Count() : gridRowCount(); | |
| 973 GridSpan crossDirectionPositions = GridResolvedPosition::resolveGridPosition
sFromAutoPlacementPosition(*style(), gridItem, crossDirection, GridResolvedPosit
ion(endOfCrossDirection)); | |
| 974 return adoptPtr(new GridCoordinate(specifiedDirection == ForColumns ? crossD
irectionPositions : specifiedPositions, specifiedDirection == ForColumns ? speci
fiedPositions : crossDirectionPositions)); | |
| 975 } | |
| 976 | |
| 977 void RenderGrid::placeSpecifiedMajorAxisItemsOnGrid(const Vector<LayoutBox*>& au
toGridItems) | |
| 978 { | |
| 979 bool isForColumns = autoPlacementMajorAxisDirection() == ForColumns; | |
| 980 bool isGridAutoFlowDense = style()->isGridAutoFlowAlgorithmDense(); | |
| 981 | |
| 982 // Mapping between the major axis tracks (rows or columns) and the last auto
-placed item's position inserted on | |
| 983 // that track. This is needed to implement "sparse" packing for items locked
to a given track. | |
| 984 // See http://dev.w3.org/csswg/css-grid/#auto-placement-algo | |
| 985 HashMap<unsigned, unsigned, DefaultHash<unsigned>::Hash, WTF::UnsignedWithZe
roKeyHashTraits<unsigned>> minorAxisCursors; | |
| 986 | |
| 987 for (const auto& autoGridItem : autoGridItems) { | |
| 988 OwnPtr<GridSpan> majorAxisPositions = GridResolvedPosition::resolveGridP
ositionsFromStyle(*style(), *autoGridItem, autoPlacementMajorAxisDirection()); | |
| 989 GridSpan minorAxisPositions = GridResolvedPosition::resolveGridPositions
FromAutoPlacementPosition(*style(), *autoGridItem, autoPlacementMinorAxisDirecti
on(), GridResolvedPosition(0)); | |
| 990 unsigned majorAxisInitialPosition = majorAxisPositions->resolvedInitialP
osition.toInt(); | |
| 991 | |
| 992 GridIterator iterator(m_grid, autoPlacementMajorAxisDirection(), majorAx
isPositions->resolvedInitialPosition.toInt(), isGridAutoFlowDense ? 0 : minorAxi
sCursors.get(majorAxisInitialPosition)); | |
| 993 OwnPtr<GridCoordinate> emptyGridArea = iterator.nextEmptyGridArea(majorA
xisPositions->integerSpan(), minorAxisPositions.integerSpan()); | |
| 994 if (!emptyGridArea) | |
| 995 emptyGridArea = createEmptyGridAreaAtSpecifiedPositionsOutsideGrid(*
autoGridItem, autoPlacementMajorAxisDirection(), *majorAxisPositions); | |
| 996 insertItemIntoGrid(*autoGridItem, *emptyGridArea); | |
| 997 | |
| 998 if (!isGridAutoFlowDense) | |
| 999 minorAxisCursors.set(majorAxisInitialPosition, isForColumns ? emptyG
ridArea->rows.resolvedInitialPosition.toInt() : emptyGridArea->columns.resolvedI
nitialPosition.toInt()); | |
| 1000 } | |
| 1001 } | |
| 1002 | |
| 1003 void RenderGrid::placeAutoMajorAxisItemsOnGrid(const Vector<LayoutBox*>& autoGri
dItems) | |
| 1004 { | |
| 1005 std::pair<size_t, size_t> autoPlacementCursor = std::make_pair(0, 0); | |
| 1006 bool isGridAutoFlowDense = style()->isGridAutoFlowAlgorithmDense(); | |
| 1007 | |
| 1008 for (const auto& autoGridItem : autoGridItems) { | |
| 1009 placeAutoMajorAxisItemOnGrid(*autoGridItem, autoPlacementCursor); | |
| 1010 | |
| 1011 // If grid-auto-flow is dense, reset auto-placement cursor. | |
| 1012 if (isGridAutoFlowDense) { | |
| 1013 autoPlacementCursor.first = 0; | |
| 1014 autoPlacementCursor.second = 0; | |
| 1015 } | |
| 1016 } | |
| 1017 } | |
| 1018 | |
| 1019 void RenderGrid::placeAutoMajorAxisItemOnGrid(LayoutBox& gridItem, std::pair<siz
e_t, size_t>& autoPlacementCursor) | |
| 1020 { | |
| 1021 OwnPtr<GridSpan> minorAxisPositions = GridResolvedPosition::resolveGridPosit
ionsFromStyle(*style(), gridItem, autoPlacementMinorAxisDirection()); | |
| 1022 ASSERT(!GridResolvedPosition::resolveGridPositionsFromStyle(*style(), gridIt
em, autoPlacementMajorAxisDirection())); | |
| 1023 GridSpan majorAxisPositions = GridResolvedPosition::resolveGridPositionsFrom
AutoPlacementPosition(*style(), gridItem, autoPlacementMajorAxisDirection(), Gri
dResolvedPosition(0)); | |
| 1024 | |
| 1025 const size_t endOfMajorAxis = (autoPlacementMajorAxisDirection() == ForColum
ns) ? gridColumnCount() : gridRowCount(); | |
| 1026 size_t majorAxisAutoPlacementCursor = autoPlacementMajorAxisDirection() == F
orColumns ? autoPlacementCursor.second : autoPlacementCursor.first; | |
| 1027 size_t minorAxisAutoPlacementCursor = autoPlacementMajorAxisDirection() == F
orColumns ? autoPlacementCursor.first : autoPlacementCursor.second; | |
| 1028 | |
| 1029 OwnPtr<GridCoordinate> emptyGridArea; | |
| 1030 if (minorAxisPositions) { | |
| 1031 // Move to the next track in major axis if initial position in minor axi
s is before auto-placement cursor. | |
| 1032 if (minorAxisPositions->resolvedInitialPosition.toInt() < minorAxisAutoP
lacementCursor) | |
| 1033 majorAxisAutoPlacementCursor++; | |
| 1034 | |
| 1035 if (majorAxisAutoPlacementCursor < endOfMajorAxis) { | |
| 1036 GridIterator iterator(m_grid, autoPlacementMinorAxisDirection(), min
orAxisPositions->resolvedInitialPosition.toInt(), majorAxisAutoPlacementCursor); | |
| 1037 emptyGridArea = iterator.nextEmptyGridArea(minorAxisPositions->integ
erSpan(), majorAxisPositions.integerSpan()); | |
| 1038 } | |
| 1039 | |
| 1040 if (!emptyGridArea) | |
| 1041 emptyGridArea = createEmptyGridAreaAtSpecifiedPositionsOutsideGrid(g
ridItem, autoPlacementMinorAxisDirection(), *minorAxisPositions); | |
| 1042 } else { | |
| 1043 GridSpan minorAxisPositions = GridResolvedPosition::resolveGridPositions
FromAutoPlacementPosition(*style(), gridItem, autoPlacementMinorAxisDirection(),
GridResolvedPosition(0)); | |
| 1044 | |
| 1045 for (size_t majorAxisIndex = majorAxisAutoPlacementCursor; majorAxisInde
x < endOfMajorAxis; ++majorAxisIndex) { | |
| 1046 GridIterator iterator(m_grid, autoPlacementMajorAxisDirection(), maj
orAxisIndex, minorAxisAutoPlacementCursor); | |
| 1047 emptyGridArea = iterator.nextEmptyGridArea(majorAxisPositions.intege
rSpan(), minorAxisPositions.integerSpan()); | |
| 1048 | |
| 1049 if (emptyGridArea) { | |
| 1050 // Check that it fits in the minor axis direction, as we shouldn
't grow in that direction here (it was already managed in populateExplicitGridAn
dOrderIterator()). | |
| 1051 GridResolvedPosition minorAxisFinalPositionIndex = autoPlacement
MinorAxisDirection() == ForColumns ? emptyGridArea->columns.resolvedFinalPositio
n : emptyGridArea->rows.resolvedFinalPosition; | |
| 1052 const size_t endOfMinorAxis = autoPlacementMinorAxisDirection()
== ForColumns ? gridColumnCount() : gridRowCount(); | |
| 1053 if (minorAxisFinalPositionIndex.toInt() < endOfMinorAxis) | |
| 1054 break; | |
| 1055 | |
| 1056 // Discard empty grid area as it does not fit in the minor axis
direction. | |
| 1057 // We don't need to create a new empty grid area yet as we might
find a valid one in the next iteration. | |
| 1058 emptyGridArea = nullptr; | |
| 1059 } | |
| 1060 | |
| 1061 // As we're moving to the next track in the major axis we should res
et the auto-placement cursor in the minor axis. | |
| 1062 minorAxisAutoPlacementCursor = 0; | |
| 1063 } | |
| 1064 | |
| 1065 if (!emptyGridArea) | |
| 1066 emptyGridArea = createEmptyGridAreaAtSpecifiedPositionsOutsideGrid(g
ridItem, autoPlacementMinorAxisDirection(), minorAxisPositions); | |
| 1067 } | |
| 1068 | |
| 1069 insertItemIntoGrid(gridItem, *emptyGridArea); | |
| 1070 // Move auto-placement cursor to the new position. | |
| 1071 autoPlacementCursor.first = emptyGridArea->rows.resolvedInitialPosition.toIn
t(); | |
| 1072 autoPlacementCursor.second = emptyGridArea->columns.resolvedInitialPosition.
toInt(); | |
| 1073 } | |
| 1074 | |
| 1075 GridTrackSizingDirection RenderGrid::autoPlacementMajorAxisDirection() const | |
| 1076 { | |
| 1077 return style()->isGridAutoFlowDirectionColumn() ? ForColumns : ForRows; | |
| 1078 } | |
| 1079 | |
| 1080 GridTrackSizingDirection RenderGrid::autoPlacementMinorAxisDirection() const | |
| 1081 { | |
| 1082 return style()->isGridAutoFlowDirectionColumn() ? ForRows : ForColumns; | |
| 1083 } | |
| 1084 | |
| 1085 void RenderGrid::dirtyGrid() | |
| 1086 { | |
| 1087 // Even if this could be redundant, it could be seen as a defensive strategy
against | |
| 1088 // style changes events happening during the layout phase or even while the
painting process | |
| 1089 // is still ongoing. | |
| 1090 // Forcing a new layout for the Grid render would cancel any ongoing paintin
g and ensure | |
| 1091 // the grid and its children are correctly laid out according to the new sty
le rules. | |
| 1092 setNeedsLayout(); | |
| 1093 | |
| 1094 m_grid.resize(0); | |
| 1095 m_gridItemCoordinate.clear(); | |
| 1096 m_gridIsDirty = true; | |
| 1097 m_gridItemsOverflowingGridArea.resize(0); | |
| 1098 m_gridItemsIndexesMap.clear(); | |
| 1099 } | |
| 1100 | |
| 1101 void RenderGrid::layoutGridItems() | |
| 1102 { | |
| 1103 placeItemsOnGrid(); | |
| 1104 | |
| 1105 LayoutUnit availableSpaceForColumns = availableLogicalWidth(); | |
| 1106 LayoutUnit availableSpaceForRows = availableLogicalHeight(IncludeMarginBorde
rPadding); | |
| 1107 GridSizingData sizingData(gridColumnCount(), gridRowCount()); | |
| 1108 computeUsedBreadthOfGridTracks(ForColumns, sizingData, availableSpaceForColu
mns); | |
| 1109 ASSERT(tracksAreWiderThanMinTrackBreadth(ForColumns, sizingData.columnTracks
)); | |
| 1110 computeUsedBreadthOfGridTracks(ForRows, sizingData, availableSpaceForRows); | |
| 1111 ASSERT(tracksAreWiderThanMinTrackBreadth(ForRows, sizingData.rowTracks)); | |
| 1112 | |
| 1113 populateGridPositions(sizingData, availableSpaceForColumns, availableSpaceFo
rRows); | |
| 1114 m_gridItemsOverflowingGridArea.resize(0); | |
| 1115 | |
| 1116 LayoutUnit columnOffset = contentPositionAndDistributionColumnOffset(availab
leSpaceForColumns, style()->justifyContent(), style()->justifyContentDistributio
n(), style()->justifyContentOverflowAlignment(), m_columnPositions.size() - 1); | |
| 1117 LayoutUnit rowOffset = contentPositionAndDistributionRowOffset(availableSpac
eForRows, style()->alignContent(), style()->alignContentDistribution(), style()-
>alignContentOverflowAlignment(), m_rowPositions.size() - 1); | |
| 1118 LayoutSize contentPositionOffset(columnOffset, rowOffset); | |
| 1119 | |
| 1120 for (LayoutBox* child = firstChildBox(); child; child = child->nextSiblingBo
x()) { | |
| 1121 if (child->isOutOfFlowPositioned()) { | |
| 1122 child->containingBlock()->insertPositionedObject(child); | |
| 1123 continue; | |
| 1124 } | |
| 1125 | |
| 1126 // Because the grid area cannot be styled, we don't need to adjust | |
| 1127 // the grid breadth to account for 'box-sizing'. | |
| 1128 LayoutUnit oldOverrideContainingBlockContentLogicalWidth = child->hasOve
rrideContainingBlockLogicalWidth() ? child->overrideContainingBlockContentLogica
lWidth() : LayoutUnit(); | |
| 1129 LayoutUnit oldOverrideContainingBlockContentLogicalHeight = child->hasOv
errideContainingBlockLogicalHeight() ? child->overrideContainingBlockContentLogi
calHeight() : LayoutUnit(); | |
| 1130 | |
| 1131 LayoutUnit overrideContainingBlockContentLogicalWidth = gridAreaBreadthF
orChild(*child, ForColumns, sizingData.columnTracks); | |
| 1132 LayoutUnit overrideContainingBlockContentLogicalHeight = gridAreaBreadth
ForChild(*child, ForRows, sizingData.rowTracks); | |
| 1133 | |
| 1134 SubtreeLayoutScope layoutScope(*child); | |
| 1135 if (oldOverrideContainingBlockContentLogicalWidth != overrideContainingB
lockContentLogicalWidth || (oldOverrideContainingBlockContentLogicalHeight != ov
errideContainingBlockContentLogicalHeight && child->hasRelativeLogicalHeight())) | |
| 1136 layoutScope.setNeedsLayout(child); | |
| 1137 | |
| 1138 child->setOverrideContainingBlockContentLogicalWidth(overrideContainingB
lockContentLogicalWidth); | |
| 1139 child->setOverrideContainingBlockContentLogicalHeight(overrideContaining
BlockContentLogicalHeight); | |
| 1140 | |
| 1141 // Stretching logic might force a child layout, so we need to run it bef
ore the layoutIfNeeded | |
| 1142 // call to avoid unnecessary relayouts. This might imply that child marg
ins, needed to correctly | |
| 1143 // determine the available space before stretching, are not set yet. | |
| 1144 applyStretchAlignmentToChildIfNeeded(*child, overrideContainingBlockCont
entLogicalHeight); | |
| 1145 | |
| 1146 child->layoutIfNeeded(); | |
| 1147 | |
| 1148 #if ENABLE(ASSERT) | |
| 1149 const GridCoordinate& coordinate = cachedGridCoordinate(*child); | |
| 1150 ASSERT(coordinate.columns.resolvedInitialPosition.toInt() < sizingData.c
olumnTracks.size()); | |
| 1151 ASSERT(coordinate.rows.resolvedInitialPosition.toInt() < sizingData.rowT
racks.size()); | |
| 1152 #endif | |
| 1153 child->setLogicalLocation(findChildLogicalPosition(*child, contentPositi
onOffset)); | |
| 1154 | |
| 1155 // Keep track of children overflowing their grid area as we might need t
o paint them even if the grid-area is | |
| 1156 // not visible | |
| 1157 if (child->logicalHeight() > overrideContainingBlockContentLogicalHeight | |
| 1158 || child->logicalWidth() > overrideContainingBlockContentLogicalWidt
h) | |
| 1159 m_gridItemsOverflowingGridArea.append(child); | |
| 1160 } | |
| 1161 | |
| 1162 for (const auto& row : sizingData.rowTracks) | |
| 1163 setLogicalHeight(logicalHeight() + row.baseSize()); | |
| 1164 | |
| 1165 // Min / max logical height is handled by the call to updateLogicalHeight in
layoutBlock. | |
| 1166 | |
| 1167 setLogicalHeight(logicalHeight() + borderAndPaddingLogicalHeight()); | |
| 1168 } | |
| 1169 | |
| 1170 void RenderGrid::layoutPositionedObjects(bool relayoutChildren, PositionedLayout
Behavior info) | |
| 1171 { | |
| 1172 TrackedRendererListHashSet* positionedDescendants = positionedObjects(); | |
| 1173 if (!positionedDescendants) | |
| 1174 return; | |
| 1175 | |
| 1176 bool containerHasHorizontalWritingMode = isHorizontalWritingMode(); | |
| 1177 for (auto* child : *positionedDescendants) { | |
| 1178 bool hasOrthogonalWritingMode = child->isHorizontalWritingMode() != cont
ainerHasHorizontalWritingMode; | |
| 1179 if (hasOrthogonalWritingMode) { | |
| 1180 // FIXME: Properly support orthogonal writing mode. | |
| 1181 continue; | |
| 1182 } | |
| 1183 | |
| 1184 // FIXME: Detect properly if start/end is auto for inexistent named grid
lines. | |
| 1185 bool columnStartIsAuto = child->style()->gridColumnStart().isAuto(); | |
| 1186 LayoutUnit columnOffset = LayoutUnit(0); | |
| 1187 LayoutUnit columnBreadth = LayoutUnit(0); | |
| 1188 offsetAndBreadthForPositionedChild(*child, ForColumns, columnStartIsAuto
, child->style()->gridColumnEnd().isAuto(), columnOffset, columnBreadth); | |
| 1189 bool rowStartIsAuto = child->style()->gridRowStart().isAuto(); | |
| 1190 LayoutUnit rowOffset = LayoutUnit(0); | |
| 1191 LayoutUnit rowBreadth = LayoutUnit(0); | |
| 1192 offsetAndBreadthForPositionedChild(*child, ForRows, rowStartIsAuto, chil
d->style()->gridRowEnd().isAuto(), rowOffset, rowBreadth); | |
| 1193 | |
| 1194 child->setOverrideContainingBlockContentLogicalWidth(columnBreadth); | |
| 1195 child->setOverrideContainingBlockContentLogicalHeight(rowBreadth); | |
| 1196 child->setExtraInlineOffset(columnOffset); | |
| 1197 child->setExtraBlockOffset(rowOffset); | |
| 1198 | |
| 1199 if (child->parent() == this) { | |
| 1200 // If column/row start is not auto the padding has been already comp
uted in offsetAndBreadthForPositionedChild(). | |
| 1201 Layer* childLayer = child->layer(); | |
| 1202 if (columnStartIsAuto) | |
| 1203 childLayer->setStaticInlinePosition(borderAndPaddingStart()); | |
| 1204 else | |
| 1205 childLayer->setStaticInlinePosition(borderStart() + columnOffset
); | |
| 1206 if (rowStartIsAuto) | |
| 1207 childLayer->setStaticBlockPosition(borderAndPaddingBefore()); | |
| 1208 else | |
| 1209 childLayer->setStaticBlockPosition(borderBefore() + rowOffset); | |
| 1210 } | |
| 1211 } | |
| 1212 | |
| 1213 RenderBlock::layoutPositionedObjects(relayoutChildren, info); | |
| 1214 } | |
| 1215 | |
| 1216 void RenderGrid::offsetAndBreadthForPositionedChild(const LayoutBox& child, Grid
TrackSizingDirection direction, bool startIsAuto, bool endIsAuto, LayoutUnit& of
fset, LayoutUnit& breadth) | |
| 1217 { | |
| 1218 ASSERT(child.isHorizontalWritingMode() == isHorizontalWritingMode()); | |
| 1219 | |
| 1220 OwnPtr<GridSpan> positions = GridResolvedPosition::resolveGridPositionsFromS
tyle(*style(), child, direction); | |
| 1221 if (!positions) { | |
| 1222 offset = LayoutUnit(0); | |
| 1223 breadth = (direction == ForColumns) ? clientLogicalWidth() : clientLogic
alHeight(); | |
| 1224 return; | |
| 1225 } | |
| 1226 | |
| 1227 GridResolvedPosition firstPosition = GridResolvedPosition(0); | |
| 1228 GridResolvedPosition initialPosition = startIsAuto ? firstPosition : positio
ns->resolvedInitialPosition; | |
| 1229 GridResolvedPosition lastPosition = GridResolvedPosition((direction == ForCo
lumns ? gridColumnCount() : gridRowCount()) - 1); | |
| 1230 GridResolvedPosition finalPosition = endIsAuto ? lastPosition : positions->r
esolvedFinalPosition; | |
| 1231 | |
| 1232 // Positioned children do not grow the grid, so we need to clamp the positio
ns to avoid ending up outside of it. | |
| 1233 initialPosition = std::min<GridResolvedPosition>(initialPosition, lastPositi
on); | |
| 1234 finalPosition = std::min<GridResolvedPosition>(finalPosition, lastPosition); | |
| 1235 | |
| 1236 LayoutUnit start = startIsAuto ? LayoutUnit(0) : (direction == ForColumns) ?
m_columnPositions[initialPosition.toInt()] : m_rowPositions[initialPosition.to
Int()]; | |
| 1237 LayoutUnit end = endIsAuto ? (direction == ForColumns) ? logicalWidth() : lo
gicalHeight() : (direction == ForColumns) ? m_columnPositions[finalPosition.nex
t().toInt()] : m_rowPositions[finalPosition.next().toInt()]; | |
| 1238 | |
| 1239 breadth = end - start; | |
| 1240 | |
| 1241 if (startIsAuto) | |
| 1242 breadth -= (direction == ForColumns) ? borderStart() : borderBefore(); | |
| 1243 else | |
| 1244 start -= ((direction == ForColumns) ? borderStart() : borderBefore()); | |
| 1245 | |
| 1246 if (endIsAuto) { | |
| 1247 breadth -= (direction == ForColumns) ? borderEnd() : borderAfter(); | |
| 1248 breadth -= scrollbarLogicalWidth(); | |
| 1249 } | |
| 1250 | |
| 1251 offset = start; | |
| 1252 } | |
| 1253 | |
| 1254 GridCoordinate RenderGrid::cachedGridCoordinate(const LayoutBox& gridItem) const | |
| 1255 { | |
| 1256 ASSERT(m_gridItemCoordinate.contains(&gridItem)); | |
| 1257 return m_gridItemCoordinate.get(&gridItem); | |
| 1258 } | |
| 1259 | |
| 1260 LayoutUnit RenderGrid::gridAreaBreadthForChild(const LayoutBox& child, GridTrack
SizingDirection direction, const Vector<GridTrack>& tracks) const | |
| 1261 { | |
| 1262 const GridCoordinate& coordinate = cachedGridCoordinate(child); | |
| 1263 const GridSpan& span = (direction == ForColumns) ? coordinate.columns : coor
dinate.rows; | |
| 1264 LayoutUnit gridAreaBreadth = 0; | |
| 1265 for (GridSpan::iterator trackPosition = span.begin(); trackPosition != span.
end(); ++trackPosition) | |
| 1266 gridAreaBreadth += tracks[trackPosition.toInt()].baseSize(); | |
| 1267 return gridAreaBreadth; | |
| 1268 } | |
| 1269 | |
| 1270 void RenderGrid::populateGridPositions(const GridSizingData& sizingData, LayoutU
nit availableSpaceForColumns, LayoutUnit availableSpaceForRows) | |
| 1271 { | |
| 1272 unsigned numberOfColumnTracks = sizingData.columnTracks.size(); | |
| 1273 unsigned numberOfRowTracks = sizingData.rowTracks.size(); | |
| 1274 | |
| 1275 m_columnPositions.resize(numberOfColumnTracks + 1); | |
| 1276 m_columnPositions[0] = borderAndPaddingStart(); | |
| 1277 for (unsigned i = 0; i < numberOfColumnTracks; ++i) | |
| 1278 m_columnPositions[i + 1] = m_columnPositions[i] + sizingData.columnTrack
s[i].baseSize(); | |
| 1279 | |
| 1280 m_rowPositions.resize(numberOfRowTracks + 1); | |
| 1281 m_rowPositions[0] = borderAndPaddingBefore(); | |
| 1282 for (unsigned i = 0; i < numberOfRowTracks; ++i) | |
| 1283 m_rowPositions[i + 1] = m_rowPositions[i] + sizingData.rowTracks[i].base
Size(); | |
| 1284 } | |
| 1285 | |
| 1286 static LayoutUnit computeOverflowAlignmentOffset(OverflowAlignment overflow, Lay
outUnit startOfTrack, LayoutUnit endOfTrack, LayoutUnit childBreadth) | |
| 1287 { | |
| 1288 LayoutUnit trackBreadth = endOfTrack - startOfTrack; | |
| 1289 LayoutUnit offset = trackBreadth - childBreadth; | |
| 1290 | |
| 1291 // If overflow is 'safe', we have to make sure we don't overflow the 'start' | |
| 1292 // edge (potentially cause some data loss as the overflow is unreachable). | |
| 1293 if (overflow == OverflowAlignmentSafe) | |
| 1294 offset = std::max<LayoutUnit>(0, offset); | |
| 1295 | |
| 1296 // If we overflow our alignment container and overflow is 'true' (default),
we | |
| 1297 // ignore the overflow and just return the value regardless (which may cause
data | |
| 1298 // loss as we overflow the 'start' edge). | |
| 1299 return offset; | |
| 1300 } | |
| 1301 | |
| 1302 LayoutUnit RenderGrid::startOfColumnForChild(const LayoutBox& child) const | |
| 1303 { | |
| 1304 const GridCoordinate& coordinate = cachedGridCoordinate(child); | |
| 1305 LayoutUnit startOfColumn = m_columnPositions[coordinate.columns.resolvedInit
ialPosition.toInt()]; | |
| 1306 // The grid items should be inside the grid container's border box, that's w
hy they need to be shifted. | |
| 1307 return startOfColumn + marginStartForChild(child); | |
| 1308 } | |
| 1309 | |
| 1310 LayoutUnit RenderGrid::endOfColumnForChild(const LayoutBox& child) const | |
| 1311 { | |
| 1312 const GridCoordinate& coordinate = cachedGridCoordinate(child); | |
| 1313 LayoutUnit startOfColumn = m_columnPositions[coordinate.columns.resolvedInit
ialPosition.toInt()]; | |
| 1314 // The grid items should be inside the grid container's border box, that's w
hy they need to be shifted. | |
| 1315 LayoutUnit columnPosition = startOfColumn + marginStartForChild(child); | |
| 1316 | |
| 1317 LayoutUnit endOfColumn = m_columnPositions[coordinate.columns.resolvedFinalP
osition.next().toInt()]; | |
| 1318 // FIXME: This might not work as expected with orthogonal writing-modes. | |
| 1319 LayoutUnit offsetFromColumnPosition = computeOverflowAlignmentOffset(child.s
tyle()->justifySelfOverflowAlignment(), startOfColumn, endOfColumn, child.logica
lWidth() + child.marginLogicalWidth()); | |
| 1320 | |
| 1321 return columnPosition + offsetFromColumnPosition; | |
| 1322 } | |
| 1323 | |
| 1324 LayoutUnit RenderGrid::columnPositionLeft(const LayoutBox& child) const | |
| 1325 { | |
| 1326 if (style()->isLeftToRightDirection()) | |
| 1327 return startOfColumnForChild(child); | |
| 1328 | |
| 1329 return endOfColumnForChild(child); | |
| 1330 } | |
| 1331 | |
| 1332 LayoutUnit RenderGrid::columnPositionRight(const LayoutBox& child) const | |
| 1333 { | |
| 1334 if (!style()->isLeftToRightDirection()) | |
| 1335 return startOfColumnForChild(child); | |
| 1336 | |
| 1337 return endOfColumnForChild(child); | |
| 1338 } | |
| 1339 | |
| 1340 LayoutUnit RenderGrid::centeredColumnPositionForChild(const LayoutBox& child) co
nst | |
| 1341 { | |
| 1342 const GridCoordinate& coordinate = cachedGridCoordinate(child); | |
| 1343 LayoutUnit startOfColumn = m_columnPositions[coordinate.columns.resolvedInit
ialPosition.toInt()]; | |
| 1344 LayoutUnit endOfColumn = m_columnPositions[coordinate.columns.resolvedFinalP
osition.next().toInt()]; | |
| 1345 LayoutUnit columnPosition = startOfColumn + marginStartForChild(child); | |
| 1346 // FIXME: This might not work as expected with orthogonal writing-modes. | |
| 1347 LayoutUnit offsetFromColumnPosition = computeOverflowAlignmentOffset(child.s
tyle()->justifySelfOverflowAlignment(), startOfColumn, endOfColumn, child.logica
lWidth() + child.marginLogicalWidth()); | |
| 1348 | |
| 1349 return columnPosition + offsetFromColumnPosition / 2; | |
| 1350 } | |
| 1351 | |
| 1352 LayoutUnit RenderGrid::columnPositionForChild(const LayoutBox& child) const | |
| 1353 { | |
| 1354 bool hasOrthogonalWritingMode = child.isHorizontalWritingMode() != isHorizon
talWritingMode(); | |
| 1355 | |
| 1356 switch (LayoutStyle::resolveJustification(styleRef(), child.styleRef(), Item
PositionStretch)) { | |
| 1357 case ItemPositionSelfStart: | |
| 1358 // For orthogonal writing-modes, this computes to 'start' | |
| 1359 // FIXME: grid track sizing and positioning do not support orthogonal mo
des yet. | |
| 1360 if (hasOrthogonalWritingMode) | |
| 1361 return startOfColumnForChild(child); | |
| 1362 | |
| 1363 // self-start is based on the child's direction. That's why we need to c
heck against the grid container's direction. | |
| 1364 if (child.style()->direction() != style()->direction()) | |
| 1365 return endOfColumnForChild(child); | |
| 1366 | |
| 1367 return startOfColumnForChild(child); | |
| 1368 case ItemPositionSelfEnd: | |
| 1369 // For orthogonal writing-modes, this computes to 'start' | |
| 1370 // FIXME: grid track sizing and positioning do not support orthogonal mo
des yet. | |
| 1371 if (hasOrthogonalWritingMode) | |
| 1372 return endOfColumnForChild(child); | |
| 1373 | |
| 1374 // self-end is based on the child's direction. That's why we need to che
ck against the grid container's direction. | |
| 1375 if (child.style()->direction() != style()->direction()) | |
| 1376 return startOfColumnForChild(child); | |
| 1377 | |
| 1378 return endOfColumnForChild(child); | |
| 1379 case ItemPositionFlexStart: | |
| 1380 // Only used in flex layout, for other layout, it's equivalent to 'start
'. | |
| 1381 return startOfColumnForChild(child); | |
| 1382 case ItemPositionFlexEnd: | |
| 1383 // Only used in flex layout, for other layout, it's equivalent to 'end'. | |
| 1384 return endOfColumnForChild(child); | |
| 1385 case ItemPositionLeft: | |
| 1386 return columnPositionLeft(child); | |
| 1387 case ItemPositionRight: | |
| 1388 return columnPositionRight(child); | |
| 1389 case ItemPositionCenter: | |
| 1390 return centeredColumnPositionForChild(child); | |
| 1391 case ItemPositionStart: | |
| 1392 return startOfColumnForChild(child); | |
| 1393 case ItemPositionEnd: | |
| 1394 return endOfColumnForChild(child); | |
| 1395 case ItemPositionAuto: | |
| 1396 break; | |
| 1397 case ItemPositionStretch: | |
| 1398 return startOfColumnForChild(child); | |
| 1399 case ItemPositionBaseline: | |
| 1400 case ItemPositionLastBaseline: | |
| 1401 // FIXME: Implement the previous values. For now, we always 'start' alig
n the child. | |
| 1402 return startOfColumnForChild(child); | |
| 1403 } | |
| 1404 | |
| 1405 ASSERT_NOT_REACHED(); | |
| 1406 return 0; | |
| 1407 } | |
| 1408 | |
| 1409 LayoutUnit RenderGrid::endOfRowForChild(const LayoutBox& child) const | |
| 1410 { | |
| 1411 const GridCoordinate& coordinate = cachedGridCoordinate(child); | |
| 1412 | |
| 1413 LayoutUnit startOfRow = m_rowPositions[coordinate.rows.resolvedInitialPositi
on.toInt()]; | |
| 1414 // The grid items should be inside the grid container's border box, that's w
hy they need to be shifted. | |
| 1415 LayoutUnit rowPosition = startOfRow + marginBeforeForChild(child); | |
| 1416 | |
| 1417 LayoutUnit endOfRow = m_rowPositions[coordinate.rows.resolvedFinalPosition.n
ext().toInt()]; | |
| 1418 LayoutUnit offsetFromRowPosition = computeOverflowAlignmentOffset(child.styl
e()->alignSelfOverflowAlignment(), startOfRow, endOfRow, child.logicalHeight() +
child.marginLogicalHeight()); | |
| 1419 | |
| 1420 return rowPosition + offsetFromRowPosition; | |
| 1421 } | |
| 1422 | |
| 1423 LayoutUnit RenderGrid::startOfRowForChild(const LayoutBox& child) const | |
| 1424 { | |
| 1425 const GridCoordinate& coordinate = cachedGridCoordinate(child); | |
| 1426 | |
| 1427 LayoutUnit startOfRow = m_rowPositions[coordinate.rows.resolvedInitialPositi
on.toInt()]; | |
| 1428 // The grid items should be inside the grid container's border box, that's w
hy they need to be shifted. | |
| 1429 LayoutUnit rowPosition = startOfRow + marginBeforeForChild(child); | |
| 1430 | |
| 1431 return rowPosition; | |
| 1432 } | |
| 1433 | |
| 1434 LayoutUnit RenderGrid::centeredRowPositionForChild(const LayoutBox& child) const | |
| 1435 { | |
| 1436 const GridCoordinate& coordinate = cachedGridCoordinate(child); | |
| 1437 | |
| 1438 // The grid items should be inside the grid container's border box, that's w
hy they need to be shifted. | |
| 1439 LayoutUnit startOfRow = m_rowPositions[coordinate.rows.resolvedInitialPositi
on.toInt()]; | |
| 1440 LayoutUnit endOfRow = m_rowPositions[coordinate.rows.resolvedFinalPosition.n
ext().toInt()]; | |
| 1441 LayoutUnit rowPosition = startOfRow + marginBeforeForChild(child); | |
| 1442 LayoutUnit offsetFromRowPosition = computeOverflowAlignmentOffset(child.styl
e()->alignSelfOverflowAlignment(), startOfRow, endOfRow, child.logicalHeight() +
child.marginLogicalHeight()); | |
| 1443 | |
| 1444 return rowPosition + offsetFromRowPosition / 2; | |
| 1445 } | |
| 1446 | |
| 1447 static inline LayoutUnit constrainedChildIntrinsicContentLogicalHeight(const Lay
outBox& child) | |
| 1448 { | |
| 1449 LayoutUnit childIntrinsicContentLogicalHeight = child.intrinsicContentLogica
lHeight(); | |
| 1450 return child.constrainLogicalHeightByMinMax(childIntrinsicContentLogicalHeig
ht + child.borderAndPaddingLogicalHeight(), childIntrinsicContentLogicalHeight); | |
| 1451 } | |
| 1452 | |
| 1453 bool RenderGrid::allowedToStretchLogicalHeightForChild(const LayoutBox& child) c
onst | |
| 1454 { | |
| 1455 return child.style()->logicalHeight().isAuto() && !child.style()->marginBefo
reUsing(style()).isAuto() && !child.style()->marginAfterUsing(style()).isAuto(); | |
| 1456 } | |
| 1457 | |
| 1458 // FIXME: This logic is shared by RenderFlexibleBox, so it should be moved to La
youtBox. | |
| 1459 bool RenderGrid::needToStretchChildLogicalHeight(const LayoutBox& child) const | |
| 1460 { | |
| 1461 if (LayoutStyle::resolveAlignment(styleRef(), child.styleRef(), ItemPosition
Stretch) != ItemPositionStretch) | |
| 1462 return false; | |
| 1463 | |
| 1464 return isHorizontalWritingMode() && child.style()->height().isAuto(); | |
| 1465 } | |
| 1466 | |
| 1467 // FIXME: This logic is shared by RenderFlexibleBox, so it should be moved to La
youtBox. | |
| 1468 LayoutUnit RenderGrid::childIntrinsicHeight(const LayoutBox& child) const | |
| 1469 { | |
| 1470 if (child.isHorizontalWritingMode() && needToStretchChildLogicalHeight(child
)) | |
| 1471 return constrainedChildIntrinsicContentLogicalHeight(child); | |
| 1472 return child.size().height(); | |
| 1473 } | |
| 1474 | |
| 1475 // FIXME: This logic is shared by RenderFlexibleBox, so it should be moved to La
youtBox. | |
| 1476 LayoutUnit RenderGrid::childIntrinsicWidth(const LayoutBox& child) const | |
| 1477 { | |
| 1478 if (!child.isHorizontalWritingMode() && needToStretchChildLogicalHeight(chil
d)) | |
| 1479 return constrainedChildIntrinsicContentLogicalHeight(child); | |
| 1480 return child.size().width(); | |
| 1481 } | |
| 1482 | |
| 1483 // FIXME: This logic is shared by RenderFlexibleBox, so it should be moved to La
youtBox. | |
| 1484 LayoutUnit RenderGrid::intrinsicLogicalHeightForChild(const LayoutBox& child) co
nst | |
| 1485 { | |
| 1486 return isHorizontalWritingMode() ? childIntrinsicHeight(child) : childIntrin
sicWidth(child); | |
| 1487 } | |
| 1488 | |
| 1489 // FIXME: This logic is shared by RenderFlexibleBox, so it should be moved to La
youtBox. | |
| 1490 LayoutUnit RenderGrid::marginLogicalHeightForChild(const LayoutBox& child) const | |
| 1491 { | |
| 1492 return isHorizontalWritingMode() ? child.marginHeight() : child.marginWidth(
); | |
| 1493 } | |
| 1494 | |
| 1495 LayoutUnit RenderGrid::computeMarginLogicalHeightForChild(const LayoutBox& child
) const | |
| 1496 { | |
| 1497 LayoutUnit marginBefore; | |
| 1498 LayoutUnit marginAfter; | |
| 1499 child.computeMarginsForDirection(BlockDirection, this, child.containingBlock
LogicalWidthForContent(), child.logicalHeight(), marginBefore, marginAfter, | |
| 1500 child.style()->marginBeforeUsing(style()), | |
| 1501 child.style()->marginAfterUsing(style())); | |
| 1502 | |
| 1503 return marginBefore + marginAfter; | |
| 1504 } | |
| 1505 | |
| 1506 LayoutUnit RenderGrid::availableAlignmentSpaceForChildBeforeStretching(LayoutUni
t gridAreaBreadthForChild, const LayoutBox& child) const | |
| 1507 { | |
| 1508 LayoutUnit childMarginLogicalHeight = marginLogicalHeightForChild(child); | |
| 1509 | |
| 1510 // Because we want to avoid multiple layouts, stretching logic might be perf
ormed before | |
| 1511 // children are laid out, so we can't use the child cached values. Hence, we
need to | |
| 1512 // compute margins in order to determine the available height before stretch
ing. | |
| 1513 if (childMarginLogicalHeight == 0) | |
| 1514 childMarginLogicalHeight = computeMarginLogicalHeightForChild(child); | |
| 1515 | |
| 1516 LayoutUnit childLogicalHeight = childMarginLogicalHeight + intrinsicLogicalH
eightForChild(child); | |
| 1517 return gridAreaBreadthForChild - childLogicalHeight; | |
| 1518 } | |
| 1519 | |
| 1520 // FIXME: This logic is shared by RenderFlexibleBox, so it should be moved to La
youtBox. | |
| 1521 void RenderGrid::applyStretchAlignmentToChildIfNeeded(LayoutBox& child, LayoutUn
it gridAreaBreadthForChild) | |
| 1522 { | |
| 1523 if (LayoutStyle::resolveAlignment(styleRef(), child.styleRef(), ItemPosition
Stretch) != ItemPositionStretch) | |
| 1524 return; | |
| 1525 | |
| 1526 bool hasOrthogonalWritingMode = child.isHorizontalWritingMode() != isHorizon
talWritingMode(); | |
| 1527 if (allowedToStretchLogicalHeightForChild(child)) { | |
| 1528 // FIXME: If the child has orthogonal flow, then it already has an overr
ide height set, so use it. | |
| 1529 // FIXME: grid track sizing and positioning do not support orthogonal mo
des yet. | |
| 1530 if (!hasOrthogonalWritingMode) { | |
| 1531 LayoutUnit heightBeforeStretching = needToStretchChildLogicalHeight(
child) ? constrainedChildIntrinsicContentLogicalHeight(child) : child.logicalHei
ght(); | |
| 1532 LayoutUnit stretchedLogicalHeight = heightBeforeStretching + availab
leAlignmentSpaceForChildBeforeStretching(gridAreaBreadthForChild, child); | |
| 1533 LayoutUnit desiredLogicalHeight = child.constrainLogicalHeightByMinM
ax(stretchedLogicalHeight, heightBeforeStretching - child.borderAndPaddingLogica
lHeight()); | |
| 1534 LayoutUnit desiredLogicalContentHeight = desiredLogicalHeight - chil
d.borderAndPaddingLogicalHeight(); | |
| 1535 | |
| 1536 // FIXME: Can avoid laying out here in some cases. See https://webki
t.org/b/87905. | |
| 1537 if (desiredLogicalHeight != child.logicalHeight() || !child.hasOverr
ideHeight() || desiredLogicalContentHeight != child.overrideLogicalContentHeight
()) { | |
| 1538 child.setOverrideLogicalContentHeight(desiredLogicalContentHeigh
t); | |
| 1539 child.setLogicalHeight(0); | |
| 1540 child.forceChildLayout(); | |
| 1541 } | |
| 1542 } | |
| 1543 } | |
| 1544 } | |
| 1545 | |
| 1546 LayoutUnit RenderGrid::rowPositionForChild(const LayoutBox& child) const | |
| 1547 { | |
| 1548 bool hasOrthogonalWritingMode = child.isHorizontalWritingMode() != isHorizon
talWritingMode(); | |
| 1549 switch (LayoutStyle::resolveAlignment(styleRef(), child.styleRef(), ItemPosi
tionStretch)) { | |
| 1550 case ItemPositionSelfStart: | |
| 1551 // If orthogonal writing-modes, this computes to 'start'. | |
| 1552 // FIXME: grid track sizing and positioning do not support orthogonal mo
des yet. | |
| 1553 if (hasOrthogonalWritingMode) | |
| 1554 return startOfRowForChild(child); | |
| 1555 | |
| 1556 // self-start is based on the child's block axis direction. That's why w
e need to check against the grid container's block flow. | |
| 1557 if (child.style()->writingMode() != style()->writingMode()) | |
| 1558 return endOfRowForChild(child); | |
| 1559 | |
| 1560 return startOfRowForChild(child); | |
| 1561 case ItemPositionSelfEnd: | |
| 1562 // If orthogonal writing-modes, this computes to 'end'. | |
| 1563 // FIXME: grid track sizing and positioning do not support orthogonal mo
des yet. | |
| 1564 if (hasOrthogonalWritingMode) | |
| 1565 return endOfRowForChild(child); | |
| 1566 | |
| 1567 // self-end is based on the child's block axis direction. That's why we
need to check against the grid container's block flow. | |
| 1568 if (child.style()->writingMode() != style()->writingMode()) | |
| 1569 return startOfRowForChild(child); | |
| 1570 | |
| 1571 return endOfRowForChild(child); | |
| 1572 case ItemPositionLeft: | |
| 1573 // The alignment axis (column axis) and the inline axis are parallell in | |
| 1574 // orthogonal writing mode. | |
| 1575 // FIXME: grid track sizing and positioning do not support orthogonal mo
des yet. | |
| 1576 if (hasOrthogonalWritingMode) | |
| 1577 return startOfRowForChild(child); | |
| 1578 | |
| 1579 // Otherwise this this is equivalent to 'start'. | |
| 1580 return startOfRowForChild(child); | |
| 1581 case ItemPositionRight: | |
| 1582 // The alignment axis (column axis) and the inline axis are parallell in | |
| 1583 // orthogonal writing mode. | |
| 1584 // FIXME: grid track sizing and positioning do not support orthogonal mo
des yet. | |
| 1585 if (hasOrthogonalWritingMode) | |
| 1586 return endOfRowForChild(child); | |
| 1587 | |
| 1588 // Otherwise this this is equivalent to 'start'. | |
| 1589 return startOfRowForChild(child); | |
| 1590 case ItemPositionCenter: | |
| 1591 return centeredRowPositionForChild(child); | |
| 1592 // Only used in flex layout, for other layout, it's equivalent to 'start
'. | |
| 1593 case ItemPositionFlexStart: | |
| 1594 case ItemPositionStart: | |
| 1595 return startOfRowForChild(child); | |
| 1596 // Only used in flex layout, for other layout, it's equivalent to 'end'. | |
| 1597 case ItemPositionFlexEnd: | |
| 1598 case ItemPositionEnd: | |
| 1599 return endOfRowForChild(child); | |
| 1600 case ItemPositionStretch: | |
| 1601 return startOfRowForChild(child); | |
| 1602 case ItemPositionBaseline: | |
| 1603 case ItemPositionLastBaseline: | |
| 1604 // FIXME: Implement the ItemPositionBaseline value. For now, we always '
start' align the child. | |
| 1605 return startOfRowForChild(child); | |
| 1606 case ItemPositionAuto: | |
| 1607 break; | |
| 1608 } | |
| 1609 | |
| 1610 ASSERT_NOT_REACHED(); | |
| 1611 return 0; | |
| 1612 } | |
| 1613 | |
| 1614 ContentPosition static resolveContentDistributionFallback(ContentDistributionTyp
e distribution) | |
| 1615 { | |
| 1616 switch (distribution) { | |
| 1617 case ContentDistributionSpaceBetween: | |
| 1618 return ContentPositionStart; | |
| 1619 case ContentDistributionSpaceAround: | |
| 1620 return ContentPositionCenter; | |
| 1621 case ContentDistributionSpaceEvenly: | |
| 1622 return ContentPositionCenter; | |
| 1623 case ContentDistributionStretch: | |
| 1624 return ContentPositionStart; | |
| 1625 case ContentDistributionDefault: | |
| 1626 return ContentPositionAuto; | |
| 1627 } | |
| 1628 | |
| 1629 ASSERT_NOT_REACHED(); | |
| 1630 return ContentPositionAuto; | |
| 1631 } | |
| 1632 | |
| 1633 static inline LayoutUnit offsetToStartEdge(bool isLeftToRight, LayoutUnit availa
bleSpace) | |
| 1634 { | |
| 1635 return isLeftToRight ? LayoutUnit(0) : availableSpace; | |
| 1636 } | |
| 1637 | |
| 1638 static inline LayoutUnit offsetToEndEdge(bool isLeftToRight, LayoutUnit availabl
eSpace) | |
| 1639 { | |
| 1640 return !isLeftToRight ? LayoutUnit(0) : availableSpace; | |
| 1641 } | |
| 1642 | |
| 1643 LayoutUnit RenderGrid::contentPositionAndDistributionColumnOffset(LayoutUnit ava
ilableFreeSpace, ContentPosition position, ContentDistributionType distribution,
OverflowAlignment overflow, unsigned numberOfGridTracks) const | |
| 1644 { | |
| 1645 if (overflow == OverflowAlignmentSafe && availableFreeSpace <= 0) | |
| 1646 return 0; | |
| 1647 | |
| 1648 // FIXME: for the time being, spec states that it will always fallback for G
rids, but | |
| 1649 // discussion is ongoing. | |
| 1650 if (distribution != ContentDistributionDefault && position == ContentPositio
nAuto) | |
| 1651 position = resolveContentDistributionFallback(distribution); | |
| 1652 | |
| 1653 switch (position) { | |
| 1654 case ContentPositionLeft: | |
| 1655 return 0; | |
| 1656 case ContentPositionRight: | |
| 1657 return availableFreeSpace; | |
| 1658 case ContentPositionCenter: | |
| 1659 return availableFreeSpace / 2; | |
| 1660 case ContentPositionFlexEnd: | |
| 1661 // Only used in flex layout, for other layout, it's equivalent to 'end'. | |
| 1662 case ContentPositionEnd: | |
| 1663 return offsetToEndEdge(style()->isLeftToRightDirection(), availableFreeS
pace); | |
| 1664 case ContentPositionFlexStart: | |
| 1665 // Only used in flex layout, for other layout, it's equivalent to 'start
'. | |
| 1666 case ContentPositionStart: | |
| 1667 return offsetToStartEdge(style()->isLeftToRightDirection(), availableFre
eSpace); | |
| 1668 case ContentPositionBaseline: | |
| 1669 case ContentPositionLastBaseline: | |
| 1670 // FIXME: Implement the previous values. For now, we always 'start' alig
n. | |
| 1671 // crbug.com/234191 | |
| 1672 return offsetToStartEdge(style()->isLeftToRightDirection(), availableFre
eSpace); | |
| 1673 case ContentPositionAuto: | |
| 1674 break; | |
| 1675 } | |
| 1676 | |
| 1677 ASSERT_NOT_REACHED(); | |
| 1678 return 0; | |
| 1679 } | |
| 1680 | |
| 1681 LayoutUnit RenderGrid::contentPositionAndDistributionRowOffset(LayoutUnit availa
bleFreeSpace, ContentPosition position, ContentDistributionType distribution, Ov
erflowAlignment overflow, unsigned numberOfGridTracks) const | |
| 1682 { | |
| 1683 if (overflow == OverflowAlignmentSafe && availableFreeSpace <= 0) | |
| 1684 return 0; | |
| 1685 | |
| 1686 // FIXME: for the time being, spec states that it will always fallback for G
rids, but | |
| 1687 // discussion is ongoing. | |
| 1688 if (distribution != ContentDistributionDefault && position == ContentPositio
nAuto) | |
| 1689 position = resolveContentDistributionFallback(distribution); | |
| 1690 | |
| 1691 switch (position) { | |
| 1692 case ContentPositionLeft: | |
| 1693 // The align-content's axis is always orthogonal to the inline-axis. | |
| 1694 return 0; | |
| 1695 case ContentPositionRight: | |
| 1696 // The align-content's axis is always orthogonal to the inline-axis. | |
| 1697 return 0; | |
| 1698 case ContentPositionCenter: | |
| 1699 return availableFreeSpace / 2; | |
| 1700 case ContentPositionFlexEnd: | |
| 1701 // Only used in flex layout, for other layout, it's equivalent to 'End'. | |
| 1702 case ContentPositionEnd: | |
| 1703 return availableFreeSpace; | |
| 1704 case ContentPositionFlexStart: | |
| 1705 // Only used in flex layout, for other layout, it's equivalent to 'Start
'. | |
| 1706 case ContentPositionStart: | |
| 1707 return 0; | |
| 1708 case ContentPositionBaseline: | |
| 1709 case ContentPositionLastBaseline: | |
| 1710 // FIXME: Implement the previous values. For now, we always start align. | |
| 1711 // crbug.com/234191 | |
| 1712 return 0; | |
| 1713 case ContentPositionAuto: | |
| 1714 break; | |
| 1715 } | |
| 1716 | |
| 1717 ASSERT_NOT_REACHED(); | |
| 1718 return 0; | |
| 1719 } | |
| 1720 | |
| 1721 LayoutPoint RenderGrid::findChildLogicalPosition(const LayoutBox& child, LayoutS
ize contentAlignmentOffset) const | |
| 1722 { | |
| 1723 LayoutUnit columnPosition = columnPositionForChild(child); | |
| 1724 // We stored m_columnPositions's data ignoring the direction, hence we might
need now | |
| 1725 // to translate positions from RTL to LTR, as it's more convenient for paint
ing. | |
| 1726 if (!style()->isLeftToRightDirection()) | |
| 1727 columnPosition = (m_columnPositions[m_columnPositions.size() - 1] + bord
erAndPaddingLogicalLeft()) - columnPosition - child.logicalWidth(); | |
| 1728 | |
| 1729 // The Content Alignment offset accounts for the RTL to LTR flip. | |
| 1730 LayoutPoint childLocation(columnPosition, rowPositionForChild(child)); | |
| 1731 childLocation.move(contentAlignmentOffset); | |
| 1732 | |
| 1733 return childLocation; | |
| 1734 } | |
| 1735 | |
| 1736 void RenderGrid::paintChildren(const PaintInfo& paintInfo, const LayoutPoint& pa
intOffset) | |
| 1737 { | |
| 1738 GridPainter(*this).paintChildren(paintInfo, paintOffset); | |
| 1739 } | |
| 1740 | |
| 1741 const char* RenderGrid::renderName() const | |
| 1742 { | |
| 1743 if (isFloating()) | |
| 1744 return "RenderGrid (floating)"; | |
| 1745 if (isOutOfFlowPositioned()) | |
| 1746 return "RenderGrid (positioned)"; | |
| 1747 if (isAnonymous()) | |
| 1748 return "RenderGrid (generated)"; | |
| 1749 if (isRelPositioned()) | |
| 1750 return "RenderGrid (relative positioned)"; | |
| 1751 return "RenderGrid"; | |
| 1752 } | |
| 1753 | |
| 1754 } // namespace blink | |
| OLD | NEW |