| 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/rendering/RenderLayer.h" | |
| 30 #include "core/rendering/RenderView.h" | |
| 31 #include "core/rendering/style/GridCoordinate.h" | |
| 32 #include "platform/LengthFunctions.h" | |
| 33 | |
| 34 namespace blink { | |
| 35 | |
| 36 static const int infinity = -1; | |
| 37 | |
| 38 class GridTrack { | |
| 39 public: | |
| 40 GridTrack() | |
| 41 : m_usedBreadth(0) | |
| 42 , m_maxBreadth(0) | |
| 43 { | |
| 44 } | |
| 45 | |
| 46 void growUsedBreadth(LayoutUnit growth) | |
| 47 { | |
| 48 ASSERT(growth >= 0); | |
| 49 m_usedBreadth += growth; | |
| 50 } | |
| 51 LayoutUnit usedBreadth() const { return m_usedBreadth; } | |
| 52 | |
| 53 void growMaxBreadth(LayoutUnit growth) | |
| 54 { | |
| 55 if (m_maxBreadth == infinity) | |
| 56 m_maxBreadth = m_usedBreadth + growth; | |
| 57 else | |
| 58 m_maxBreadth += growth; | |
| 59 } | |
| 60 LayoutUnit maxBreadthIfNotInfinite() const | |
| 61 { | |
| 62 return (m_maxBreadth == infinity) ? m_usedBreadth : m_maxBreadth; | |
| 63 } | |
| 64 | |
| 65 LayoutUnit m_usedBreadth; | |
| 66 LayoutUnit m_maxBreadth; | |
| 67 }; | |
| 68 | |
| 69 struct GridTrackForNormalization { | |
| 70 GridTrackForNormalization(const GridTrack& track, double flex) | |
| 71 : m_track(&track) | |
| 72 , m_flex(flex) | |
| 73 , m_normalizedFlexValue(track.m_usedBreadth / flex) | |
| 74 { | |
| 75 } | |
| 76 | |
| 77 // Required by std::sort. | |
| 78 GridTrackForNormalization& operator=(const GridTrackForNormalization& o) | |
| 79 { | |
| 80 m_track = o.m_track; | |
| 81 m_flex = o.m_flex; | |
| 82 m_normalizedFlexValue = o.m_normalizedFlexValue; | |
| 83 return *this; | |
| 84 } | |
| 85 | |
| 86 const GridTrack* m_track; | |
| 87 double m_flex; | |
| 88 LayoutUnit m_normalizedFlexValue; | |
| 89 }; | |
| 90 | |
| 91 class RenderGrid::GridIterator { | |
| 92 WTF_MAKE_NONCOPYABLE(GridIterator); | |
| 93 public: | |
| 94 // |direction| is the direction that is fixed to |fixedTrackIndex| so e.g | |
| 95 // GridIterator(m_grid, ForColumns, 1) will walk over the rows of the 2nd co
lumn. | |
| 96 GridIterator(const GridRepresentation& grid, GridTrackSizingDirection direct
ion, size_t fixedTrackIndex, size_t varyingTrackIndex = 0) | |
| 97 : m_grid(grid) | |
| 98 , m_direction(direction) | |
| 99 , m_rowIndex((direction == ForColumns) ? varyingTrackIndex : fixedTrackI
ndex) | |
| 100 , m_columnIndex((direction == ForColumns) ? fixedTrackIndex : varyingTra
ckIndex) | |
| 101 , m_childIndex(0) | |
| 102 { | |
| 103 ASSERT(m_rowIndex < m_grid.size()); | |
| 104 ASSERT(m_columnIndex < m_grid[0].size()); | |
| 105 } | |
| 106 | |
| 107 RenderBox* nextGridItem() | |
| 108 { | |
| 109 ASSERT(!m_grid.isEmpty()); | |
| 110 | |
| 111 size_t& varyingTrackIndex = (m_direction == ForColumns) ? m_rowIndex : m
_columnIndex; | |
| 112 const size_t endOfVaryingTrackIndex = (m_direction == ForColumns) ? m_gr
id.size() : m_grid[0].size(); | |
| 113 for (; varyingTrackIndex < endOfVaryingTrackIndex; ++varyingTrackIndex)
{ | |
| 114 const GridCell& children = m_grid[m_rowIndex][m_columnIndex]; | |
| 115 if (m_childIndex < children.size()) | |
| 116 return children[m_childIndex++]; | |
| 117 | |
| 118 m_childIndex = 0; | |
| 119 } | |
| 120 return 0; | |
| 121 } | |
| 122 | |
| 123 bool checkEmptyCells(size_t rowSpan, size_t columnSpan) const | |
| 124 { | |
| 125 // Ignore cells outside current grid as we will grow it later if needed. | |
| 126 size_t maxRows = std::min(m_rowIndex + rowSpan, m_grid.size()); | |
| 127 size_t maxColumns = std::min(m_columnIndex + columnSpan, m_grid[0].size(
)); | |
| 128 | |
| 129 // This adds a O(N^2) behavior that shouldn't be a big deal as we expect
spanning areas to be small. | |
| 130 for (size_t row = m_rowIndex; row < maxRows; ++row) { | |
| 131 for (size_t column = m_columnIndex; column < maxColumns; ++column) { | |
| 132 const GridCell& children = m_grid[row][column]; | |
| 133 if (!children.isEmpty()) | |
| 134 return false; | |
| 135 } | |
| 136 } | |
| 137 | |
| 138 return true; | |
| 139 } | |
| 140 | |
| 141 PassOwnPtr<GridCoordinate> nextEmptyGridArea(size_t fixedTrackSpan, size_t v
aryingTrackSpan) | |
| 142 { | |
| 143 ASSERT(!m_grid.isEmpty()); | |
| 144 ASSERT(fixedTrackSpan >= 1 && varyingTrackSpan >= 1); | |
| 145 | |
| 146 size_t rowSpan = (m_direction == ForColumns) ? varyingTrackSpan : fixedT
rackSpan; | |
| 147 size_t columnSpan = (m_direction == ForColumns) ? fixedTrackSpan : varyi
ngTrackSpan; | |
| 148 | |
| 149 size_t& varyingTrackIndex = (m_direction == ForColumns) ? m_rowIndex : m
_columnIndex; | |
| 150 const size_t endOfVaryingTrackIndex = (m_direction == ForColumns) ? m_gr
id.size() : m_grid[0].size(); | |
| 151 for (; varyingTrackIndex < endOfVaryingTrackIndex; ++varyingTrackIndex)
{ | |
| 152 if (checkEmptyCells(rowSpan, columnSpan)) { | |
| 153 OwnPtr<GridCoordinate> result = adoptPtr(new GridCoordinate(Grid
Span(m_rowIndex, m_rowIndex + rowSpan - 1), GridSpan(m_columnIndex, m_columnInde
x + columnSpan - 1))); | |
| 154 // Advance the iterator to avoid an infinite loop where we would
return the same grid area over and over. | |
| 155 ++varyingTrackIndex; | |
| 156 return result.release(); | |
| 157 } | |
| 158 } | |
| 159 return nullptr; | |
| 160 } | |
| 161 | |
| 162 private: | |
| 163 const GridRepresentation& m_grid; | |
| 164 GridTrackSizingDirection m_direction; | |
| 165 size_t m_rowIndex; | |
| 166 size_t m_columnIndex; | |
| 167 size_t m_childIndex; | |
| 168 }; | |
| 169 | |
| 170 struct RenderGrid::GridSizingData { | |
| 171 WTF_MAKE_NONCOPYABLE(GridSizingData); | |
| 172 public: | |
| 173 GridSizingData(size_t gridColumnCount, size_t gridRowCount) | |
| 174 : columnTracks(gridColumnCount) | |
| 175 , rowTracks(gridRowCount) | |
| 176 { | |
| 177 } | |
| 178 | |
| 179 Vector<GridTrack> columnTracks; | |
| 180 Vector<GridTrack> rowTracks; | |
| 181 Vector<size_t> contentSizedTracksIndex; | |
| 182 | |
| 183 // Performance optimization: hold onto these Vectors until the end of Layout
to avoid repeated malloc / free. | |
| 184 Vector<LayoutUnit> distributeTrackVector; | |
| 185 Vector<GridTrack*> filteredTracks; | |
| 186 }; | |
| 187 | |
| 188 RenderGrid::RenderGrid(Element* element) | |
| 189 : RenderBlock(element) | |
| 190 , m_gridIsDirty(true) | |
| 191 , m_orderIterator(this) | |
| 192 { | |
| 193 ASSERT(!childrenInline()); | |
| 194 } | |
| 195 | |
| 196 RenderGrid::~RenderGrid() | |
| 197 { | |
| 198 } | |
| 199 | |
| 200 void RenderGrid::addChild(RenderObject* newChild, RenderObject* beforeChild) | |
| 201 { | |
| 202 // If the new requested beforeChild is not one of our children is because it
's wrapped by an anonymous container. If | |
| 203 // we do not special case this situation we could end up calling addChild()
twice for the newChild, one with the | |
| 204 // initial beforeChild and another one with its parent. | |
| 205 if (beforeChild && beforeChild->parent() != this) { | |
| 206 ASSERT(beforeChild->parent()->isAnonymous()); | |
| 207 beforeChild = splitAnonymousBoxesAroundChild(beforeChild); | |
| 208 dirtyGrid(); | |
| 209 } | |
| 210 | |
| 211 RenderBlock::addChild(newChild, beforeChild); | |
| 212 | |
| 213 if (gridIsDirty()) | |
| 214 return; | |
| 215 | |
| 216 if (!newChild->isBox()) { | |
| 217 dirtyGrid(); | |
| 218 return; | |
| 219 } | |
| 220 | |
| 221 // FIXME: Implement properly "stack" value in auto-placement algorithm. | |
| 222 if (!style()->isGridAutoFlowAlgorithmStack()) { | |
| 223 // The grid needs to be recomputed as it might contain auto-placed items
that will change their position. | |
| 224 dirtyGrid(); | |
| 225 return; | |
| 226 } | |
| 227 | |
| 228 RenderBox* newChildBox = toRenderBox(newChild); | |
| 229 OwnPtr<GridSpan> rowPositions = GridResolvedPosition::resolveGridPositionsFr
omStyle(*style(), *newChildBox, ForRows); | |
| 230 OwnPtr<GridSpan> columnPositions = GridResolvedPosition::resolveGridPosition
sFromStyle(*style(), *newChildBox, ForColumns); | |
| 231 if (!rowPositions || !columnPositions) { | |
| 232 // The new child requires the auto-placement algorithm to run so we need
to recompute the grid fully. | |
| 233 dirtyGrid(); | |
| 234 return; | |
| 235 } else { | |
| 236 insertItemIntoGrid(newChildBox, GridCoordinate(*rowPositions, *columnPos
itions)); | |
| 237 addChildToIndexesMap(newChildBox); | |
| 238 } | |
| 239 } | |
| 240 | |
| 241 void RenderGrid::addChildToIndexesMap(RenderBox* child) | |
| 242 { | |
| 243 ASSERT(!m_gridItemsIndexesMap.contains(child)); | |
| 244 RenderBox* sibling = child->nextSiblingBox(); | |
| 245 bool lastSibling = !sibling; | |
| 246 | |
| 247 if (lastSibling) | |
| 248 sibling = child->previousSiblingBox(); | |
| 249 | |
| 250 size_t index = 0; | |
| 251 if (sibling) | |
| 252 index = lastSibling ? m_gridItemsIndexesMap.get(sibling) + 1 : m_gridIte
msIndexesMap.get(sibling); | |
| 253 | |
| 254 if (sibling && !lastSibling) { | |
| 255 for (; sibling; sibling = sibling->nextSiblingBox()) | |
| 256 m_gridItemsIndexesMap.set(sibling, m_gridItemsIndexesMap.get(sibling
) + 1); | |
| 257 } | |
| 258 | |
| 259 m_gridItemsIndexesMap.set(child, index); | |
| 260 } | |
| 261 | |
| 262 void RenderGrid::removeChild(RenderObject* child) | |
| 263 { | |
| 264 RenderBlock::removeChild(child); | |
| 265 | |
| 266 if (gridIsDirty()) | |
| 267 return; | |
| 268 | |
| 269 ASSERT(child->isBox()); | |
| 270 | |
| 271 // FIXME: Implement properly "stack" value in auto-placement algorithm. | |
| 272 if (!style()->isGridAutoFlowAlgorithmStack()) { | |
| 273 // The grid needs to be recomputed as it might contain auto-placed items
that will change their position. | |
| 274 dirtyGrid(); | |
| 275 return; | |
| 276 } | |
| 277 | |
| 278 const RenderBox* childBox = toRenderBox(child); | |
| 279 GridCoordinate coordinate = m_gridItemCoordinate.take(childBox); | |
| 280 | |
| 281 for (GridSpan::iterator row = coordinate.rows.begin(); row != coordinate.row
s.end(); ++row) { | |
| 282 for (GridSpan::iterator column = coordinate.columns.begin(); column != c
oordinate.columns.end(); ++column) { | |
| 283 GridCell& cell = m_grid[row.toInt()][column.toInt()]; | |
| 284 cell.remove(cell.find(childBox)); | |
| 285 } | |
| 286 } | |
| 287 | |
| 288 m_gridItemsIndexesMap.remove(childBox); | |
| 289 } | |
| 290 | |
| 291 void RenderGrid::styleDidChange(StyleDifference diff, const RenderStyle* 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() != style()->gridAutoFlow()) | |
| 305 dirtyGrid(); | |
| 306 } | |
| 307 | |
| 308 bool RenderGrid::explicitGridDidResize(const RenderStyle* oldStyle) const | |
| 309 { | |
| 310 return oldStyle->gridTemplateColumns().size() != style()->gridTemplateColumn
s().size() | |
| 311 || oldStyle->gridTemplateRows().size() != style()->gridTemplateRows().si
ze(); | |
| 312 } | |
| 313 | |
| 314 bool RenderGrid::namedGridLinesDefinitionDidChange(const RenderStyle* oldStyle)
const | |
| 315 { | |
| 316 return oldStyle->namedGridRowLines() != style()->namedGridRowLines() | |
| 317 || oldStyle->namedGridColumnLines() != style()->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 RenderBox::layout
Block and Render*FlexibleBox::layoutBlock. | |
| 328 // It would be nice to refactor some of the duplicate code. | |
| 329 LayoutState state(*this, locationOffset()); | |
| 330 | |
| 331 LayoutSize previousSize = size(); | |
| 332 | |
| 333 setLogicalHeight(0); | |
| 334 updateLogicalWidth(); | |
| 335 | |
| 336 layoutGridItems(); | |
| 337 | |
| 338 LayoutUnit oldClientAfterEdge = clientLogicalBottom(); | |
| 339 updateLogicalHeight(); | |
| 340 | |
| 341 if (size() != previousSize) | |
| 342 relayoutChildren = true; | |
| 343 | |
| 344 layoutPositionedObjects(relayoutChildren || isDocumentElement()); | |
| 345 | |
| 346 computeOverflow(oldClientAfterEdge); | |
| 347 | |
| 348 updateLayerTransformAfterLayout(); | |
| 349 | |
| 350 // Update our scroll information if we're overflow:auto/scroll/hidden now th
at we know if | |
| 351 // we overflow or not. | |
| 352 if (hasOverflowClip()) | |
| 353 layer()->scrollableArea()->updateAfterLayout(); | |
| 354 | |
| 355 clearNeedsLayout(); | |
| 356 } | |
| 357 | |
| 358 void RenderGrid::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, Layo
utUnit& maxLogicalWidth) const | |
| 359 { | |
| 360 const_cast<RenderGrid*>(this)->placeItemsOnGrid(); | |
| 361 | |
| 362 GridSizingData sizingData(gridColumnCount(), gridRowCount()); | |
| 363 LayoutUnit availableLogicalSpace = 0; | |
| 364 const_cast<RenderGrid*>(this)->computeUsedBreadthOfGridTracks(ForColumns, si
zingData, availableLogicalSpace); | |
| 365 | |
| 366 for (size_t i = 0; i < sizingData.columnTracks.size(); ++i) { | |
| 367 LayoutUnit minTrackBreadth = sizingData.columnTracks[i].m_usedBreadth; | |
| 368 LayoutUnit maxTrackBreadth = sizingData.columnTracks[i].m_maxBreadth; | |
| 369 maxTrackBreadth = std::max(maxTrackBreadth, minTrackBreadth); | |
| 370 | |
| 371 minLogicalWidth += minTrackBreadth; | |
| 372 maxLogicalWidth += maxTrackBreadth; | |
| 373 | |
| 374 // FIXME: This should add in the scrollbarWidth (e.g. see RenderFlexible
Box). | |
| 375 } | |
| 376 } | |
| 377 | |
| 378 void RenderGrid::computePreferredLogicalWidths() | |
| 379 { | |
| 380 ASSERT(preferredLogicalWidthsDirty()); | |
| 381 | |
| 382 m_minPreferredLogicalWidth = 0; | |
| 383 m_maxPreferredLogicalWidth = 0; | |
| 384 | |
| 385 // FIXME: We don't take our own logical width into account. Once we do, we n
eed to make sure | |
| 386 // we apply (and test the interaction with) min-width / max-width. | |
| 387 | |
| 388 computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogi
calWidth); | |
| 389 | |
| 390 LayoutUnit borderAndPaddingInInlineDirection = borderAndPaddingLogicalWidth(
); | |
| 391 m_minPreferredLogicalWidth += borderAndPaddingInInlineDirection; | |
| 392 m_maxPreferredLogicalWidth += borderAndPaddingInInlineDirection; | |
| 393 | |
| 394 clearPreferredLogicalWidthsDirty(); | |
| 395 } | |
| 396 | |
| 397 void RenderGrid::computeUsedBreadthOfGridTracks(GridTrackSizingDirection directi
on, GridSizingData& sizingData) | |
| 398 { | |
| 399 LayoutUnit availableLogicalSpace = (direction == ForColumns) ? availableLogi
calWidth() : availableLogicalHeight(IncludeMarginBorderPadding); | |
| 400 computeUsedBreadthOfGridTracks(direction, sizingData, availableLogicalSpace)
; | |
| 401 } | |
| 402 | |
| 403 bool RenderGrid::gridElementIsShrinkToFit() | |
| 404 { | |
| 405 return isFloatingOrOutOfFlowPositioned(); | |
| 406 } | |
| 407 | |
| 408 void RenderGrid::computeUsedBreadthOfGridTracks(GridTrackSizingDirection directi
on, GridSizingData& sizingData, LayoutUnit& availableLogicalSpace) | |
| 409 { | |
| 410 Vector<GridTrack>& tracks = (direction == ForColumns) ? sizingData.columnTra
cks : sizingData.rowTracks; | |
| 411 Vector<size_t> flexibleSizedTracksIndex; | |
| 412 sizingData.contentSizedTracksIndex.shrink(0); | |
| 413 | |
| 414 // 1. Initialize per Grid track variables. | |
| 415 for (size_t i = 0; i < tracks.size(); ++i) { | |
| 416 GridTrack& track = tracks[i]; | |
| 417 const GridTrackSize& trackSize = gridTrackSize(direction, i); | |
| 418 const GridLength& minTrackBreadth = trackSize.minTrackBreadth(); | |
| 419 const GridLength& maxTrackBreadth = trackSize.maxTrackBreadth(); | |
| 420 | |
| 421 track.m_usedBreadth = computeUsedBreadthOfMinLength(direction, minTrackB
readth); | |
| 422 track.m_maxBreadth = computeUsedBreadthOfMaxLength(direction, maxTrackBr
eadth, track.m_usedBreadth); | |
| 423 | |
| 424 if (track.m_maxBreadth != infinity) | |
| 425 track.m_maxBreadth = std::max(track.m_maxBreadth, track.m_usedBreadt
h); | |
| 426 | |
| 427 if (trackSize.isContentSized()) | |
| 428 sizingData.contentSizedTracksIndex.append(i); | |
| 429 if (trackSize.maxTrackBreadth().isFlex()) | |
| 430 flexibleSizedTracksIndex.append(i); | |
| 431 } | |
| 432 | |
| 433 // 2. Resolve content-based TrackSizingFunctions. | |
| 434 if (!sizingData.contentSizedTracksIndex.isEmpty()) | |
| 435 resolveContentBasedTrackSizingFunctions(direction, sizingData, available
LogicalSpace); | |
| 436 | |
| 437 for (size_t i = 0; i < tracks.size(); ++i) { | |
| 438 ASSERT(tracks[i].m_maxBreadth != infinity); | |
| 439 availableLogicalSpace -= tracks[i].m_usedBreadth; | |
| 440 } | |
| 441 | |
| 442 const bool hasUndefinedRemainingSpace = (direction == ForRows) ? style()->lo
gicalHeight().isAuto() : gridElementIsShrinkToFit(); | |
| 443 | |
| 444 if (!hasUndefinedRemainingSpace && availableLogicalSpace <= 0) | |
| 445 return; | |
| 446 | |
| 447 // 3. Grow all Grid tracks in GridTracks from their UsedBreadth up to their
MaxBreadth value until | |
| 448 // availableLogicalSpace (RemainingSpace in the specs) is exhausted. | |
| 449 const size_t tracksSize = tracks.size(); | |
| 450 if (!hasUndefinedRemainingSpace) { | |
| 451 Vector<GridTrack*> tracksForDistribution(tracksSize); | |
| 452 for (size_t i = 0; i < tracksSize; ++i) | |
| 453 tracksForDistribution[i] = tracks.data() + i; | |
| 454 | |
| 455 distributeSpaceToTracks(tracksForDistribution, 0, &GridTrack::usedBreadt
h, &GridTrack::growUsedBreadth, sizingData, availableLogicalSpace); | |
| 456 } else { | |
| 457 for (size_t i = 0; i < tracksSize; ++i) | |
| 458 tracks[i].m_usedBreadth = tracks[i].m_maxBreadth; | |
| 459 } | |
| 460 | |
| 461 if (flexibleSizedTracksIndex.isEmpty()) | |
| 462 return; | |
| 463 | |
| 464 // 4. Grow all Grid tracks having a fraction as the MaxTrackSizingFunction. | |
| 465 double normalizedFractionBreadth = 0; | |
| 466 if (!hasUndefinedRemainingSpace) { | |
| 467 normalizedFractionBreadth = computeNormalizedFractionBreadth(tracks, Gri
dSpan(0, tracks.size() - 1), direction, availableLogicalSpace); | |
| 468 } else { | |
| 469 for (size_t i = 0; i < flexibleSizedTracksIndex.size(); ++i) { | |
| 470 const size_t trackIndex = flexibleSizedTracksIndex[i]; | |
| 471 const GridTrackSize& trackSize = gridTrackSize(direction, trackIndex
); | |
| 472 normalizedFractionBreadth = std::max(normalizedFractionBreadth, trac
ks[trackIndex].m_usedBreadth / trackSize.maxTrackBreadth().flex()); | |
| 473 } | |
| 474 | |
| 475 for (size_t i = 0; i < flexibleSizedTracksIndex.size(); ++i) { | |
| 476 GridIterator iterator(m_grid, direction, flexibleSizedTracksIndex[i]
); | |
| 477 while (RenderBox* gridItem = iterator.nextGridItem()) { | |
| 478 const GridCoordinate coordinate = cachedGridCoordinate(gridItem)
; | |
| 479 const GridSpan span = (direction == ForColumns) ? coordinate.col
umns : coordinate.rows; | |
| 480 | |
| 481 // Do not include already processed items. | |
| 482 if (i > 0 && span.resolvedInitialPosition.toInt() <= flexibleSiz
edTracksIndex[i - 1]) | |
| 483 continue; | |
| 484 | |
| 485 double itemNormalizedFlexBreadth = computeNormalizedFractionBrea
dth(tracks, span, direction, maxContentForChild(gridItem, direction, sizingData.
columnTracks)); | |
| 486 normalizedFractionBreadth = std::max(normalizedFractionBreadth,
itemNormalizedFlexBreadth); | |
| 487 } | |
| 488 } | |
| 489 } | |
| 490 | |
| 491 for (size_t i = 0; i < flexibleSizedTracksIndex.size(); ++i) { | |
| 492 const size_t trackIndex = flexibleSizedTracksIndex[i]; | |
| 493 const GridTrackSize& trackSize = gridTrackSize(direction, trackIndex); | |
| 494 | |
| 495 tracks[trackIndex].m_usedBreadth = std::max<LayoutUnit>(tracks[trackInde
x].m_usedBreadth, normalizedFractionBreadth * trackSize.maxTrackBreadth().flex()
); | |
| 496 } | |
| 497 } | |
| 498 | |
| 499 LayoutUnit RenderGrid::computeUsedBreadthOfMinLength(GridTrackSizingDirection di
rection, const GridLength& gridLength) const | |
| 500 { | |
| 501 if (gridLength.isFlex()) | |
| 502 return 0; | |
| 503 | |
| 504 const Length& trackLength = gridLength.length(); | |
| 505 ASSERT(!trackLength.isAuto()); | |
| 506 if (trackLength.isSpecified()) | |
| 507 return computeUsedBreadthOfSpecifiedLength(direction, trackLength); | |
| 508 | |
| 509 ASSERT(trackLength.isMinContent() || trackLength.isMaxContent()); | |
| 510 return 0; | |
| 511 } | |
| 512 | |
| 513 LayoutUnit RenderGrid::computeUsedBreadthOfMaxLength(GridTrackSizingDirection di
rection, const GridLength& gridLength, LayoutUnit usedBreadth) const | |
| 514 { | |
| 515 if (gridLength.isFlex()) | |
| 516 return usedBreadth; | |
| 517 | |
| 518 const Length& trackLength = gridLength.length(); | |
| 519 ASSERT(!trackLength.isAuto()); | |
| 520 if (trackLength.isSpecified()) { | |
| 521 LayoutUnit computedBreadth = computeUsedBreadthOfSpecifiedLength(directi
on, trackLength); | |
| 522 ASSERT(computedBreadth != infinity); | |
| 523 return computedBreadth; | |
| 524 } | |
| 525 | |
| 526 ASSERT(trackLength.isMinContent() || trackLength.isMaxContent()); | |
| 527 return infinity; | |
| 528 } | |
| 529 | |
| 530 LayoutUnit RenderGrid::computeUsedBreadthOfSpecifiedLength(GridTrackSizingDirect
ion direction, const Length& trackLength) const | |
| 531 { | |
| 532 ASSERT(trackLength.isSpecified()); | |
| 533 // FIXME: The -1 here should be replaced by whatever the intrinsic height of
the grid is. | |
| 534 return valueForLength(trackLength, direction == ForColumns ? logicalWidth()
: computeContentLogicalHeight(style()->logicalHeight(), -1)); | |
| 535 } | |
| 536 | |
| 537 static bool sortByGridNormalizedFlexValue(const GridTrackForNormalization& track
1, const GridTrackForNormalization& track2) | |
| 538 { | |
| 539 return track1.m_normalizedFlexValue < track2.m_normalizedFlexValue; | |
| 540 } | |
| 541 | |
| 542 double RenderGrid::computeNormalizedFractionBreadth(Vector<GridTrack>& tracks, c
onst GridSpan& tracksSpan, GridTrackSizingDirection direction, LayoutUnit availa
bleLogicalSpace) const | |
| 543 { | |
| 544 // |availableLogicalSpace| already accounts for the used breadths so no need
to remove it here. | |
| 545 | |
| 546 Vector<GridTrackForNormalization> tracksForNormalization; | |
| 547 for (GridSpan::iterator resolvedPosition = tracksSpan.begin(); resolvedPosit
ion != tracksSpan.end(); ++resolvedPosition) { | |
| 548 const GridTrackSize& trackSize = gridTrackSize(direction, resolvedPositi
on.toInt()); | |
| 549 if (!trackSize.maxTrackBreadth().isFlex()) | |
| 550 continue; | |
| 551 | |
| 552 tracksForNormalization.append(GridTrackForNormalization(tracks[resolvedP
osition.toInt()], trackSize.maxTrackBreadth().flex())); | |
| 553 } | |
| 554 | |
| 555 // The function is not called if we don't have <flex> grid tracks | |
| 556 ASSERT(!tracksForNormalization.isEmpty()); | |
| 557 | |
| 558 std::sort(tracksForNormalization.begin(), tracksForNormalization.end(), sort
ByGridNormalizedFlexValue); | |
| 559 | |
| 560 // These values work together: as we walk over our grid tracks, we increase
fractionValueBasedOnGridItemsRatio | |
| 561 // to match a grid track's usedBreadth to <flex> ratio until the total fract
ions sized grid tracks wouldn't | |
| 562 // fit into availableLogicalSpaceIgnoringFractionTracks. | |
| 563 double accumulatedFractions = 0; | |
| 564 LayoutUnit fractionValueBasedOnGridItemsRatio = 0; | |
| 565 LayoutUnit availableLogicalSpaceIgnoringFractionTracks = availableLogicalSpa
ce; | |
| 566 | |
| 567 for (size_t i = 0; i < tracksForNormalization.size(); ++i) { | |
| 568 const GridTrackForNormalization& track = tracksForNormalization[i]; | |
| 569 if (track.m_normalizedFlexValue > fractionValueBasedOnGridItemsRatio) { | |
| 570 // If the normalized flex value (we ordered |tracksForNormalization|
by increasing normalized flex value) | |
| 571 // will make us overflow our container, then stop. We have the previ
ous step's ratio is the best fit. | |
| 572 if (track.m_normalizedFlexValue * accumulatedFractions > availableLo
gicalSpaceIgnoringFractionTracks) | |
| 573 break; | |
| 574 | |
| 575 fractionValueBasedOnGridItemsRatio = track.m_normalizedFlexValue; | |
| 576 } | |
| 577 | |
| 578 accumulatedFractions += track.m_flex; | |
| 579 // This item was processed so we re-add its used breadth to the availabl
e space to accurately count the remaining space. | |
| 580 availableLogicalSpaceIgnoringFractionTracks += track.m_track->m_usedBrea
dth; | |
| 581 } | |
| 582 | |
| 583 return availableLogicalSpaceIgnoringFractionTracks / accumulatedFractions; | |
| 584 } | |
| 585 | |
| 586 const GridTrackSize& RenderGrid::gridTrackSize(GridTrackSizingDirection directio
n, size_t i) const | |
| 587 { | |
| 588 const Vector<GridTrackSize>& trackStyles = (direction == ForColumns) ? style
()->gridTemplateColumns() : style()->gridTemplateRows(); | |
| 589 if (i >= trackStyles.size()) | |
| 590 return (direction == ForColumns) ? style()->gridAutoColumns() : style()-
>gridAutoRows(); | |
| 591 | |
| 592 const GridTrackSize& trackSize = trackStyles[i]; | |
| 593 // If the logical width/height of the grid container is indefinite, percenta
ge values are treated as <auto>. | |
| 594 if (trackSize.isPercentage()) { | |
| 595 Length logicalSize = direction == ForColumns ? style()->logicalWidth() :
style()->logicalHeight(); | |
| 596 if (logicalSize.isIntrinsicOrAuto()) { | |
| 597 DEFINE_STATIC_LOCAL(GridTrackSize, autoTrackSize, (Length(Auto))); | |
| 598 return autoTrackSize; | |
| 599 } | |
| 600 } | |
| 601 | |
| 602 return trackSize; | |
| 603 } | |
| 604 | |
| 605 LayoutUnit RenderGrid::logicalHeightForChild(RenderBox* child, Vector<GridTrack>
& columnTracks) | |
| 606 { | |
| 607 SubtreeLayoutScope layoutScope(*child); | |
| 608 LayoutUnit oldOverrideContainingBlockContentLogicalWidth = child->hasOverrid
eContainingBlockLogicalWidth() ? child->overrideContainingBlockContentLogicalWid
th() : LayoutUnit(); | |
| 609 LayoutUnit overrideContainingBlockContentLogicalWidth = gridAreaBreadthForCh
ild(child, ForColumns, columnTracks); | |
| 610 if (child->style()->logicalHeight().isPercent() || oldOverrideContainingBloc
kContentLogicalWidth != overrideContainingBlockContentLogicalWidth) | |
| 611 layoutScope.setNeedsLayout(child); | |
| 612 | |
| 613 child->setOverrideContainingBlockContentLogicalWidth(overrideContainingBlock
ContentLogicalWidth); | |
| 614 // If |child| has a percentage logical height, we shouldn't let it override
its intrinsic height, which is | |
| 615 // what we are interested in here. Thus we need to set the override logical
height to -1 (no possible resolution). | |
| 616 child->setOverrideContainingBlockContentLogicalHeight(-1); | |
| 617 child->layoutIfNeeded(); | |
| 618 return child->logicalHeight() + child->marginLogicalHeight(); | |
| 619 } | |
| 620 | |
| 621 LayoutUnit RenderGrid::minContentForChild(RenderBox* child, GridTrackSizingDirec
tion direction, Vector<GridTrack>& columnTracks) | |
| 622 { | |
| 623 if (direction == ForColumns) { | |
| 624 // FIXME: It's unclear if we should return the intrinsic width or the pr
eferred width. | |
| 625 // See http://lists.w3.org/Archives/Public/www-style/2013Jan/0245.html | |
| 626 return child->minPreferredLogicalWidth() + marginIntrinsicLogicalWidthFo
rChild(child); | |
| 627 } | |
| 628 | |
| 629 return logicalHeightForChild(child, columnTracks); | |
| 630 } | |
| 631 | |
| 632 LayoutUnit RenderGrid::maxContentForChild(RenderBox* child, GridTrackSizingDirec
tion direction, Vector<GridTrack>& columnTracks) | |
| 633 { | |
| 634 if (direction == ForColumns) { | |
| 635 // FIXME: It's unclear if we should return the intrinsic width or the pr
eferred width. | |
| 636 // See http://lists.w3.org/Archives/Public/www-style/2013Jan/0245.html | |
| 637 return child->maxPreferredLogicalWidth() + marginIntrinsicLogicalWidthFo
rChild(child); | |
| 638 } | |
| 639 | |
| 640 return logicalHeightForChild(child, columnTracks); | |
| 641 } | |
| 642 | |
| 643 size_t RenderGrid::gridItemSpan(const RenderBox* child, GridTrackSizingDirection
direction) | |
| 644 { | |
| 645 GridCoordinate childCoordinate = cachedGridCoordinate(child); | |
| 646 GridSpan childSpan = (direction == ForRows) ? childCoordinate.rows : childCo
ordinate.columns; | |
| 647 | |
| 648 return childSpan.resolvedFinalPosition.toInt() - childSpan.resolvedInitialPo
sition.toInt() + 1; | |
| 649 } | |
| 650 | |
| 651 typedef std::pair<RenderBox*, size_t> GridItemWithSpan; | |
| 652 | |
| 653 // This function sorts by span (.second in the pair) but also places pointers (.
first in the pair) to the same object in | |
| 654 // consecutive positions so duplicates could be easily removed with std::unique(
) for example. | |
| 655 static bool gridItemWithSpanSorter(const GridItemWithSpan& item1, const GridItem
WithSpan& item2) | |
| 656 { | |
| 657 if (item1.second != item2.second) | |
| 658 return item1.second < item2.second; | |
| 659 | |
| 660 return item1.first < item2.first; | |
| 661 } | |
| 662 | |
| 663 static bool uniquePointerInPair(const GridItemWithSpan& item1, const GridItemWit
hSpan& item2) | |
| 664 { | |
| 665 return item1.first == item2.first; | |
| 666 } | |
| 667 | |
| 668 void RenderGrid::resolveContentBasedTrackSizingFunctions(GridTrackSizingDirectio
n direction, GridSizingData& sizingData, LayoutUnit& availableLogicalSpace) | |
| 669 { | |
| 670 // FIXME: Split the grid tracks into groups that doesn't overlap a <flex> gr
id track (crbug.com/235258). | |
| 671 | |
| 672 for (size_t i = 0; i < sizingData.contentSizedTracksIndex.size(); ++i) { | |
| 673 size_t trackIndex = sizingData.contentSizedTracksIndex[i]; | |
| 674 GridIterator iterator(m_grid, direction, trackIndex); | |
| 675 Vector<GridItemWithSpan> itemsSortedByIncreasingSpan; | |
| 676 | |
| 677 while (RenderBox* gridItem = iterator.nextGridItem()) | |
| 678 itemsSortedByIncreasingSpan.append(std::make_pair(gridItem, gridItem
Span(gridItem, direction))); | |
| 679 std::stable_sort(itemsSortedByIncreasingSpan.begin(), itemsSortedByIncre
asingSpan.end(), gridItemWithSpanSorter); | |
| 680 Vector<GridItemWithSpan>::iterator end = std::unique(itemsSortedByIncrea
singSpan.begin(), itemsSortedByIncreasingSpan.end(), uniquePointerInPair); | |
| 681 | |
| 682 for (Vector<GridItemWithSpan>::iterator it = itemsSortedByIncreasingSpan
.begin(); it != end; ++it) { | |
| 683 RenderBox* gridItem = it->first; | |
| 684 resolveContentBasedTrackSizingFunctionsForItems(direction, sizingDat
a, gridItem, &GridTrackSize::hasMinOrMaxContentMinTrackBreadth, &RenderGrid::min
ContentForChild, &GridTrack::usedBreadth, &GridTrack::growUsedBreadth); | |
| 685 resolveContentBasedTrackSizingFunctionsForItems(direction, sizingDat
a, gridItem, &GridTrackSize::hasMaxContentMinTrackBreadth, &RenderGrid::maxConte
ntForChild, &GridTrack::usedBreadth, &GridTrack::growUsedBreadth); | |
| 686 resolveContentBasedTrackSizingFunctionsForItems(direction, sizingDat
a, gridItem, &GridTrackSize::hasMinOrMaxContentMaxTrackBreadth, &RenderGrid::min
ContentForChild, &GridTrack::maxBreadthIfNotInfinite, &GridTrack::growMaxBreadth
); | |
| 687 resolveContentBasedTrackSizingFunctionsForItems(direction, sizingDat
a, gridItem, &GridTrackSize::hasMaxContentMaxTrackBreadth, &RenderGrid::maxConte
ntForChild, &GridTrack::maxBreadthIfNotInfinite, &GridTrack::growMaxBreadth); | |
| 688 } | |
| 689 | |
| 690 GridTrack& track = (direction == ForColumns) ? sizingData.columnTracks[t
rackIndex] : sizingData.rowTracks[trackIndex]; | |
| 691 if (track.m_maxBreadth == infinity) | |
| 692 track.m_maxBreadth = track.m_usedBreadth; | |
| 693 } | |
| 694 } | |
| 695 | |
| 696 void RenderGrid::resolveContentBasedTrackSizingFunctionsForItems(GridTrackSizing
Direction direction, GridSizingData& sizingData, RenderBox* gridItem, FilterFunc
tion filterFunction, SizingFunction sizingFunction, AccumulatorGetter trackGette
r, AccumulatorGrowFunction trackGrowthFunction) | |
| 697 { | |
| 698 const GridCoordinate coordinate = cachedGridCoordinate(gridItem); | |
| 699 const GridResolvedPosition initialTrackPosition = (direction == ForColumns)
? coordinate.columns.resolvedInitialPosition : coordinate.rows.resolvedInitialPo
sition; | |
| 700 const GridResolvedPosition finalTrackPosition = (direction == ForColumns) ?
coordinate.columns.resolvedFinalPosition : coordinate.rows.resolvedFinalPosition
; | |
| 701 | |
| 702 sizingData.filteredTracks.shrink(0); | |
| 703 for (GridResolvedPosition trackPosition = initialTrackPosition; trackPositio
n <= finalTrackPosition; ++trackPosition) { | |
| 704 const GridTrackSize& trackSize = gridTrackSize(direction, trackPosition.
toInt()); | |
| 705 if (!(trackSize.*filterFunction)()) | |
| 706 continue; | |
| 707 | |
| 708 GridTrack& track = (direction == ForColumns) ? sizingData.columnTracks[t
rackPosition.toInt()] : sizingData.rowTracks[trackPosition.toInt()]; | |
| 709 sizingData.filteredTracks.append(&track); | |
| 710 } | |
| 711 | |
| 712 if (sizingData.filteredTracks.isEmpty()) | |
| 713 return; | |
| 714 | |
| 715 LayoutUnit additionalBreadthSpace = (this->*sizingFunction)(gridItem, direct
ion, sizingData.columnTracks); | |
| 716 for (GridResolvedPosition trackIndexForSpace = initialTrackPosition; trackIn
dexForSpace <= finalTrackPosition; ++trackIndexForSpace) { | |
| 717 GridTrack& track = (direction == ForColumns) ? sizingData.columnTracks[t
rackIndexForSpace.toInt()] : sizingData.rowTracks[trackIndexForSpace.toInt()]; | |
| 718 additionalBreadthSpace -= (track.*trackGetter)(); | |
| 719 } | |
| 720 | |
| 721 // FIXME: We should pass different values for |tracksForGrowthAboveMaxBreadt
h|. | |
| 722 | |
| 723 // Specs mandate to floor additionalBreadthSpace (extra-space in specs) to 0
. Instead we directly avoid the function | |
| 724 // call in those cases as it will be a noop in terms of track sizing. | |
| 725 if (additionalBreadthSpace > 0) | |
| 726 distributeSpaceToTracks(sizingData.filteredTracks, &sizingData.filteredT
racks, trackGetter, trackGrowthFunction, sizingData, additionalBreadthSpace); | |
| 727 } | |
| 728 | |
| 729 static bool sortByGridTrackGrowthPotential(const GridTrack* track1, const GridTr
ack* track2) | |
| 730 { | |
| 731 if (track1->m_maxBreadth == infinity) | |
| 732 return track2->m_maxBreadth == infinity; | |
| 733 | |
| 734 if (track2->m_maxBreadth == infinity) | |
| 735 return true; | |
| 736 | |
| 737 return (track1->m_maxBreadth - track1->m_usedBreadth) < (track2->m_maxBreadt
h - track2->m_usedBreadth); | |
| 738 } | |
| 739 | |
| 740 void RenderGrid::distributeSpaceToTracks(Vector<GridTrack*>& tracks, Vector<Grid
Track*>* tracksForGrowthAboveMaxBreadth, AccumulatorGetter trackGetter, Accumula
torGrowFunction trackGrowthFunction, GridSizingData& sizingData, LayoutUnit& ava
ilableLogicalSpace) | |
| 741 { | |
| 742 ASSERT(availableLogicalSpace > 0); | |
| 743 std::sort(tracks.begin(), tracks.end(), sortByGridTrackGrowthPotential); | |
| 744 | |
| 745 size_t tracksSize = tracks.size(); | |
| 746 sizingData.distributeTrackVector.resize(tracksSize); | |
| 747 | |
| 748 for (size_t i = 0; i < tracksSize; ++i) { | |
| 749 GridTrack& track = *tracks[i]; | |
| 750 LayoutUnit availableLogicalSpaceShare = availableLogicalSpace / (tracksS
ize - i); | |
| 751 LayoutUnit trackBreadth = (tracks[i]->*trackGetter)(); | |
| 752 LayoutUnit growthShare = track.m_maxBreadth == infinity ? availableLogic
alSpaceShare : std::min(availableLogicalSpaceShare, track.m_maxBreadth - trackBr
eadth); | |
| 753 ASSERT(growthShare != infinity); | |
| 754 sizingData.distributeTrackVector[i] = trackBreadth; | |
| 755 // We should never shrink any grid track or else we can't guarantee we a
bide by our min-sizing function. | |
| 756 if (growthShare > 0) { | |
| 757 sizingData.distributeTrackVector[i] += growthShare; | |
| 758 availableLogicalSpace -= growthShare; | |
| 759 } | |
| 760 } | |
| 761 | |
| 762 if (availableLogicalSpace > 0 && tracksForGrowthAboveMaxBreadth) { | |
| 763 tracksSize = tracksForGrowthAboveMaxBreadth->size(); | |
| 764 for (size_t i = 0; i < tracksSize; ++i) { | |
| 765 LayoutUnit growthShare = availableLogicalSpace / (tracksSize - i); | |
| 766 sizingData.distributeTrackVector[i] += growthShare; | |
| 767 availableLogicalSpace -= growthShare; | |
| 768 } | |
| 769 } | |
| 770 | |
| 771 for (size_t i = 0; i < tracksSize; ++i) { | |
| 772 LayoutUnit growth = sizingData.distributeTrackVector[i] - (tracks[i]->*t
rackGetter)(); | |
| 773 if (growth >= 0) | |
| 774 (tracks[i]->*trackGrowthFunction)(growth); | |
| 775 } | |
| 776 } | |
| 777 | |
| 778 #if ENABLE(ASSERT) | |
| 779 bool RenderGrid::tracksAreWiderThanMinTrackBreadth(GridTrackSizingDirection dire
ction, const Vector<GridTrack>& tracks) | |
| 780 { | |
| 781 for (size_t i = 0; i < tracks.size(); ++i) { | |
| 782 const GridTrackSize& trackSize = gridTrackSize(direction, i); | |
| 783 const GridLength& minTrackBreadth = trackSize.minTrackBreadth(); | |
| 784 if (computeUsedBreadthOfMinLength(direction, minTrackBreadth) > tracks[i
].m_usedBreadth) | |
| 785 return false; | |
| 786 } | |
| 787 return true; | |
| 788 } | |
| 789 #endif | |
| 790 | |
| 791 void RenderGrid::ensureGridSize(size_t maximumRowIndex, size_t maximumColumnInde
x) | |
| 792 { | |
| 793 const size_t oldRowSize = gridRowCount(); | |
| 794 if (maximumRowIndex >= oldRowSize) { | |
| 795 m_grid.grow(maximumRowIndex + 1); | |
| 796 for (size_t row = oldRowSize; row < gridRowCount(); ++row) | |
| 797 m_grid[row].grow(gridColumnCount()); | |
| 798 } | |
| 799 | |
| 800 if (maximumColumnIndex >= gridColumnCount()) { | |
| 801 for (size_t row = 0; row < gridRowCount(); ++row) | |
| 802 m_grid[row].grow(maximumColumnIndex + 1); | |
| 803 } | |
| 804 } | |
| 805 | |
| 806 void RenderGrid::insertItemIntoGrid(RenderBox* child, const GridCoordinate& coor
dinate) | |
| 807 { | |
| 808 ensureGridSize(coordinate.rows.resolvedFinalPosition.toInt(), coordinate.col
umns.resolvedFinalPosition.toInt()); | |
| 809 | |
| 810 for (GridSpan::iterator row = coordinate.rows.begin(); row != coordinate.row
s.end(); ++row) { | |
| 811 for (GridSpan::iterator column = coordinate.columns.begin(); column != c
oordinate.columns.end(); ++column) | |
| 812 m_grid[row.toInt()][column.toInt()].append(child); | |
| 813 } | |
| 814 | |
| 815 RELEASE_ASSERT(!m_gridItemCoordinate.contains(child)); | |
| 816 m_gridItemCoordinate.set(child, coordinate); | |
| 817 } | |
| 818 | |
| 819 void RenderGrid::placeItemsOnGrid() | |
| 820 { | |
| 821 if (!gridIsDirty()) | |
| 822 return; | |
| 823 | |
| 824 ASSERT(m_gridItemCoordinate.isEmpty()); | |
| 825 | |
| 826 populateExplicitGridAndOrderIterator(); | |
| 827 | |
| 828 // We clear the dirty bit here as the grid sizes have been updated, this mea
ns | |
| 829 // that we can safely call gridRowCount() / gridColumnCount(). | |
| 830 m_gridIsDirty = false; | |
| 831 | |
| 832 Vector<RenderBox*> autoMajorAxisAutoGridItems; | |
| 833 Vector<RenderBox*> specifiedMajorAxisAutoGridItems; | |
| 834 for (RenderBox* child = m_orderIterator.first(); child; child = m_orderItera
tor.next()) { | |
| 835 // FIXME: We never re-resolve positions if the grid is grown during auto
-placement which may lead auto / <integer> | |
| 836 // positions to not match the author's intent. The specification is uncl
ear on what should be done in this case. | |
| 837 OwnPtr<GridSpan> rowPositions = GridResolvedPosition::resolveGridPositio
nsFromStyle(*style(), *child, ForRows); | |
| 838 OwnPtr<GridSpan> columnPositions = GridResolvedPosition::resolveGridPosi
tionsFromStyle(*style(), *child, ForColumns); | |
| 839 if (!rowPositions || !columnPositions) { | |
| 840 GridSpan* majorAxisPositions = (autoPlacementMajorAxisDirection() ==
ForColumns) ? columnPositions.get() : rowPositions.get(); | |
| 841 if (!majorAxisPositions) | |
| 842 autoMajorAxisAutoGridItems.append(child); | |
| 843 else | |
| 844 specifiedMajorAxisAutoGridItems.append(child); | |
| 845 continue; | |
| 846 } | |
| 847 insertItemIntoGrid(child, GridCoordinate(*rowPositions, *columnPositions
)); | |
| 848 } | |
| 849 | |
| 850 ASSERT(gridRowCount() >= style()->gridTemplateRows().size()); | |
| 851 ASSERT(gridColumnCount() >= style()->gridTemplateColumns().size()); | |
| 852 | |
| 853 // FIXME: Implement properly "stack" value in auto-placement algorithm. | |
| 854 if (style()->isGridAutoFlowAlgorithmStack()) { | |
| 855 // If we did collect some grid items, they won't be placed thus never la
id out. | |
| 856 ASSERT(!autoMajorAxisAutoGridItems.size()); | |
| 857 ASSERT(!specifiedMajorAxisAutoGridItems.size()); | |
| 858 return; | |
| 859 } | |
| 860 | |
| 861 placeSpecifiedMajorAxisItemsOnGrid(specifiedMajorAxisAutoGridItems); | |
| 862 placeAutoMajorAxisItemsOnGrid(autoMajorAxisAutoGridItems); | |
| 863 | |
| 864 m_grid.shrinkToFit(); | |
| 865 } | |
| 866 | |
| 867 void RenderGrid::populateExplicitGridAndOrderIterator() | |
| 868 { | |
| 869 OrderIteratorPopulator populator(m_orderIterator); | |
| 870 | |
| 871 size_t maximumRowIndex = std::max<size_t>(1, GridResolvedPosition::explicitG
ridRowCount(*style())); | |
| 872 size_t maximumColumnIndex = std::max<size_t>(1, GridResolvedPosition::explic
itGridColumnCount(*style())); | |
| 873 | |
| 874 ASSERT(m_gridItemsIndexesMap.isEmpty()); | |
| 875 size_t childIndex = 0; | |
| 876 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBo
x()) { | |
| 877 populator.collectChild(child); | |
| 878 m_gridItemsIndexesMap.set(child, childIndex++); | |
| 879 | |
| 880 // This function bypasses the cache (cachedGridCoordinate()) as it is us
ed to build it. | |
| 881 OwnPtr<GridSpan> rowPositions = GridResolvedPosition::resolveGridPositio
nsFromStyle(*style(), *child, ForRows); | |
| 882 OwnPtr<GridSpan> columnPositions = GridResolvedPosition::resolveGridPosi
tionsFromStyle(*style(), *child, ForColumns); | |
| 883 | |
| 884 // |positions| is 0 if we need to run the auto-placement algorithm. | |
| 885 if (rowPositions) { | |
| 886 maximumRowIndex = std::max<size_t>(maximumRowIndex, rowPositions->re
solvedFinalPosition.next().toInt()); | |
| 887 } else { | |
| 888 // Grow the grid for items with a definite row span, getting the lar
gest such span. | |
| 889 GridSpan positions = GridResolvedPosition::resolveGridPositionsFromA
utoPlacementPosition(*style(), *child, ForRows, GridResolvedPosition(0)); | |
| 890 maximumRowIndex = std::max<size_t>(maximumRowIndex, positions.resolv
edFinalPosition.next().toInt()); | |
| 891 } | |
| 892 | |
| 893 if (columnPositions) { | |
| 894 maximumColumnIndex = std::max<size_t>(maximumColumnIndex, columnPosi
tions->resolvedFinalPosition.next().toInt()); | |
| 895 } else { | |
| 896 // Grow the grid for items with a definite column span, getting the
largest such span. | |
| 897 GridSpan positions = GridResolvedPosition::resolveGridPositionsFromA
utoPlacementPosition(*style(), *child, ForColumns, GridResolvedPosition(0)); | |
| 898 maximumColumnIndex = std::max<size_t>(maximumColumnIndex, positions.
resolvedFinalPosition.next().toInt()); | |
| 899 } | |
| 900 } | |
| 901 | |
| 902 m_grid.grow(maximumRowIndex); | |
| 903 for (size_t i = 0; i < m_grid.size(); ++i) | |
| 904 m_grid[i].grow(maximumColumnIndex); | |
| 905 } | |
| 906 | |
| 907 PassOwnPtr<GridCoordinate> RenderGrid::createEmptyGridAreaAtSpecifiedPositionsOu
tsideGrid(const RenderBox* gridItem, GridTrackSizingDirection specifiedDirection
, const GridSpan& specifiedPositions) const | |
| 908 { | |
| 909 GridTrackSizingDirection crossDirection = specifiedDirection == ForColumns ?
ForRows : ForColumns; | |
| 910 const size_t endOfCrossDirection = crossDirection == ForColumns ? gridColumn
Count() : gridRowCount(); | |
| 911 GridSpan crossDirectionPositions = GridResolvedPosition::resolveGridPosition
sFromAutoPlacementPosition(*style(), *gridItem, crossDirection, GridResolvedPosi
tion(endOfCrossDirection)); | |
| 912 return adoptPtr(new GridCoordinate(specifiedDirection == ForColumns ? crossD
irectionPositions : specifiedPositions, specifiedDirection == ForColumns ? speci
fiedPositions : crossDirectionPositions)); | |
| 913 } | |
| 914 | |
| 915 void RenderGrid::placeSpecifiedMajorAxisItemsOnGrid(const Vector<RenderBox*>& au
toGridItems) | |
| 916 { | |
| 917 for (size_t i = 0; i < autoGridItems.size(); ++i) { | |
| 918 OwnPtr<GridSpan> majorAxisPositions = GridResolvedPosition::resolveGridP
ositionsFromStyle(*style(), *autoGridItems[i], autoPlacementMajorAxisDirection()
); | |
| 919 GridSpan minorAxisPositions = GridResolvedPosition::resolveGridPositions
FromAutoPlacementPosition(*style(), *autoGridItems[i], autoPlacementMinorAxisDir
ection(), GridResolvedPosition(0)); | |
| 920 | |
| 921 GridIterator iterator(m_grid, autoPlacementMajorAxisDirection(), majorAx
isPositions->resolvedInitialPosition.toInt()); | |
| 922 OwnPtr<GridCoordinate> emptyGridArea = iterator.nextEmptyGridArea(majorA
xisPositions->integerSpan(), minorAxisPositions.integerSpan()); | |
| 923 if (!emptyGridArea) | |
| 924 emptyGridArea = createEmptyGridAreaAtSpecifiedPositionsOutsideGrid(a
utoGridItems[i], autoPlacementMajorAxisDirection(), *majorAxisPositions); | |
| 925 insertItemIntoGrid(autoGridItems[i], *emptyGridArea); | |
| 926 } | |
| 927 } | |
| 928 | |
| 929 void RenderGrid::placeAutoMajorAxisItemsOnGrid(const Vector<RenderBox*>& autoGri
dItems) | |
| 930 { | |
| 931 std::pair<size_t, size_t> autoPlacementCursor = std::make_pair(0, 0); | |
| 932 bool isGridAutoFlowDense = style()->isGridAutoFlowAlgorithmDense(); | |
| 933 | |
| 934 for (size_t i = 0; i < autoGridItems.size(); ++i) { | |
| 935 placeAutoMajorAxisItemOnGrid(autoGridItems[i], autoPlacementCursor); | |
| 936 | |
| 937 // If grid-auto-flow is dense, reset auto-placement cursor. | |
| 938 if (isGridAutoFlowDense) { | |
| 939 autoPlacementCursor.first = 0; | |
| 940 autoPlacementCursor.second = 0; | |
| 941 } | |
| 942 } | |
| 943 } | |
| 944 | |
| 945 void RenderGrid::placeAutoMajorAxisItemOnGrid(RenderBox* gridItem, std::pair<siz
e_t, size_t>& autoPlacementCursor) | |
| 946 { | |
| 947 OwnPtr<GridSpan> minorAxisPositions = GridResolvedPosition::resolveGridPosit
ionsFromStyle(*style(), *gridItem, autoPlacementMinorAxisDirection()); | |
| 948 ASSERT(!GridResolvedPosition::resolveGridPositionsFromStyle(*style(), *gridI
tem, autoPlacementMajorAxisDirection())); | |
| 949 GridSpan majorAxisPositions = GridResolvedPosition::resolveGridPositionsFrom
AutoPlacementPosition(*style(), *gridItem, autoPlacementMajorAxisDirection(), Gr
idResolvedPosition(0)); | |
| 950 | |
| 951 const size_t endOfMajorAxis = (autoPlacementMajorAxisDirection() == ForColum
ns) ? gridColumnCount() : gridRowCount(); | |
| 952 size_t majorAxisAutoPlacementCursor = autoPlacementMajorAxisDirection() == F
orColumns ? autoPlacementCursor.second : autoPlacementCursor.first; | |
| 953 size_t minorAxisAutoPlacementCursor = autoPlacementMajorAxisDirection() == F
orColumns ? autoPlacementCursor.first : autoPlacementCursor.second; | |
| 954 | |
| 955 OwnPtr<GridCoordinate> emptyGridArea; | |
| 956 if (minorAxisPositions) { | |
| 957 // Move to the next track in major axis if initial position in minor axi
s is before auto-placement cursor. | |
| 958 if (minorAxisPositions->resolvedInitialPosition.toInt() < minorAxisAutoP
lacementCursor) | |
| 959 majorAxisAutoPlacementCursor++; | |
| 960 | |
| 961 if (majorAxisAutoPlacementCursor < endOfMajorAxis) { | |
| 962 GridIterator iterator(m_grid, autoPlacementMinorAxisDirection(), min
orAxisPositions->resolvedInitialPosition.toInt(), majorAxisAutoPlacementCursor); | |
| 963 emptyGridArea = iterator.nextEmptyGridArea(minorAxisPositions->integ
erSpan(), majorAxisPositions.integerSpan()); | |
| 964 } | |
| 965 | |
| 966 if (!emptyGridArea) | |
| 967 emptyGridArea = createEmptyGridAreaAtSpecifiedPositionsOutsideGrid(g
ridItem, autoPlacementMinorAxisDirection(), *minorAxisPositions); | |
| 968 } else { | |
| 969 GridSpan minorAxisPositions = GridResolvedPosition::resolveGridPositions
FromAutoPlacementPosition(*style(), *gridItem, autoPlacementMinorAxisDirection()
, GridResolvedPosition(0)); | |
| 970 | |
| 971 for (size_t majorAxisIndex = majorAxisAutoPlacementCursor; majorAxisInde
x < endOfMajorAxis; ++majorAxisIndex) { | |
| 972 GridIterator iterator(m_grid, autoPlacementMajorAxisDirection(), maj
orAxisIndex, minorAxisAutoPlacementCursor); | |
| 973 emptyGridArea = iterator.nextEmptyGridArea(majorAxisPositions.intege
rSpan(), minorAxisPositions.integerSpan()); | |
| 974 | |
| 975 if (emptyGridArea) { | |
| 976 // 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()). | |
| 977 GridResolvedPosition minorAxisFinalPositionIndex = autoPlacement
MinorAxisDirection() == ForColumns ? emptyGridArea->columns.resolvedFinalPositio
n : emptyGridArea->rows.resolvedFinalPosition; | |
| 978 const size_t endOfMinorAxis = autoPlacementMinorAxisDirection()
== ForColumns ? gridColumnCount() : gridRowCount(); | |
| 979 if (minorAxisFinalPositionIndex.toInt() < endOfMinorAxis) | |
| 980 break; | |
| 981 | |
| 982 // Discard empty grid area as it does not fit in the minor axis
direction. | |
| 983 // We don't need to create a new empty grid area yet as we might
find a valid one in the next iteration. | |
| 984 emptyGridArea = nullptr; | |
| 985 } | |
| 986 | |
| 987 // As we're moving to the next track in the major axis we should res
et the auto-placement cursor in the minor axis. | |
| 988 minorAxisAutoPlacementCursor = 0; | |
| 989 } | |
| 990 | |
| 991 if (!emptyGridArea) | |
| 992 emptyGridArea = createEmptyGridAreaAtSpecifiedPositionsOutsideGrid(g
ridItem, autoPlacementMinorAxisDirection(), minorAxisPositions); | |
| 993 } | |
| 994 | |
| 995 insertItemIntoGrid(gridItem, *emptyGridArea); | |
| 996 // Move auto-placement cursor to the new position. | |
| 997 autoPlacementCursor.first = emptyGridArea->rows.resolvedInitialPosition.toIn
t(); | |
| 998 autoPlacementCursor.second = emptyGridArea->columns.resolvedInitialPosition.
toInt(); | |
| 999 } | |
| 1000 | |
| 1001 GridTrackSizingDirection RenderGrid::autoPlacementMajorAxisDirection() const | |
| 1002 { | |
| 1003 return style()->isGridAutoFlowDirectionColumn() ? ForColumns : ForRows; | |
| 1004 } | |
| 1005 | |
| 1006 GridTrackSizingDirection RenderGrid::autoPlacementMinorAxisDirection() const | |
| 1007 { | |
| 1008 return style()->isGridAutoFlowDirectionColumn() ? ForRows : ForColumns; | |
| 1009 } | |
| 1010 | |
| 1011 void RenderGrid::dirtyGrid() | |
| 1012 { | |
| 1013 m_grid.resize(0); | |
| 1014 m_gridItemCoordinate.clear(); | |
| 1015 m_gridIsDirty = true; | |
| 1016 m_gridItemsOverflowingGridArea.resize(0); | |
| 1017 m_gridItemsIndexesMap.clear(); | |
| 1018 } | |
| 1019 | |
| 1020 void RenderGrid::layoutGridItems() | |
| 1021 { | |
| 1022 placeItemsOnGrid(); | |
| 1023 | |
| 1024 GridSizingData sizingData(gridColumnCount(), gridRowCount()); | |
| 1025 computeUsedBreadthOfGridTracks(ForColumns, sizingData); | |
| 1026 ASSERT(tracksAreWiderThanMinTrackBreadth(ForColumns, sizingData.columnTracks
)); | |
| 1027 computeUsedBreadthOfGridTracks(ForRows, sizingData); | |
| 1028 ASSERT(tracksAreWiderThanMinTrackBreadth(ForRows, sizingData.rowTracks)); | |
| 1029 | |
| 1030 populateGridPositions(sizingData); | |
| 1031 m_gridItemsOverflowingGridArea.resize(0); | |
| 1032 | |
| 1033 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBo
x()) { | |
| 1034 // Because the grid area cannot be styled, we don't need to adjust | |
| 1035 // the grid breadth to account for 'box-sizing'. | |
| 1036 LayoutUnit oldOverrideContainingBlockContentLogicalWidth = child->hasOve
rrideContainingBlockLogicalWidth() ? child->overrideContainingBlockContentLogica
lWidth() : LayoutUnit(); | |
| 1037 LayoutUnit oldOverrideContainingBlockContentLogicalHeight = child->hasOv
errideContainingBlockLogicalHeight() ? child->overrideContainingBlockContentLogi
calHeight() : LayoutUnit(); | |
| 1038 | |
| 1039 LayoutUnit overrideContainingBlockContentLogicalWidth = gridAreaBreadthF
orChild(child, ForColumns, sizingData.columnTracks); | |
| 1040 LayoutUnit overrideContainingBlockContentLogicalHeight = gridAreaBreadth
ForChild(child, ForRows, sizingData.rowTracks); | |
| 1041 | |
| 1042 SubtreeLayoutScope layoutScope(*child); | |
| 1043 if (oldOverrideContainingBlockContentLogicalWidth != overrideContainingB
lockContentLogicalWidth || (oldOverrideContainingBlockContentLogicalHeight != ov
errideContainingBlockContentLogicalHeight && child->hasRelativeLogicalHeight())) | |
| 1044 layoutScope.setNeedsLayout(child); | |
| 1045 | |
| 1046 child->setOverrideContainingBlockContentLogicalWidth(overrideContainingB
lockContentLogicalWidth); | |
| 1047 child->setOverrideContainingBlockContentLogicalHeight(overrideContaining
BlockContentLogicalHeight); | |
| 1048 | |
| 1049 // FIXME: Grid items should stretch to fill their cells. Once we | |
| 1050 // implement grid-{column,row}-align, we can also shrink to fit. For | |
| 1051 // now, just size as if we were a regular child. | |
| 1052 child->layoutIfNeeded(); | |
| 1053 | |
| 1054 #if ENABLE(ASSERT) | |
| 1055 const GridCoordinate& coordinate = cachedGridCoordinate(child); | |
| 1056 ASSERT(coordinate.columns.resolvedInitialPosition.toInt() < sizingData.c
olumnTracks.size()); | |
| 1057 ASSERT(coordinate.rows.resolvedInitialPosition.toInt() < sizingData.rowT
racks.size()); | |
| 1058 #endif | |
| 1059 child->setLogicalLocation(findChildLogicalPosition(child)); | |
| 1060 | |
| 1061 // Keep track of children overflowing their grid area as we might need t
o paint them even if the grid-area is | |
| 1062 // not visible | |
| 1063 if (child->logicalHeight() > overrideContainingBlockContentLogicalHeight | |
| 1064 || child->logicalWidth() > overrideContainingBlockContentLogicalWidt
h) | |
| 1065 m_gridItemsOverflowingGridArea.append(child); | |
| 1066 } | |
| 1067 | |
| 1068 for (size_t i = 0; i < sizingData.rowTracks.size(); ++i) | |
| 1069 setLogicalHeight(logicalHeight() + sizingData.rowTracks[i].m_usedBreadth
); | |
| 1070 | |
| 1071 // Min / max logical height is handled by the call to updateLogicalHeight in
layoutBlock. | |
| 1072 | |
| 1073 setLogicalHeight(logicalHeight() + borderAndPaddingLogicalHeight()); | |
| 1074 } | |
| 1075 | |
| 1076 GridCoordinate RenderGrid::cachedGridCoordinate(const RenderBox* gridItem) const | |
| 1077 { | |
| 1078 ASSERT(m_gridItemCoordinate.contains(gridItem)); | |
| 1079 return m_gridItemCoordinate.get(gridItem); | |
| 1080 } | |
| 1081 | |
| 1082 LayoutUnit RenderGrid::gridAreaBreadthForChild(const RenderBox* child, GridTrack
SizingDirection direction, const Vector<GridTrack>& tracks) const | |
| 1083 { | |
| 1084 const GridCoordinate& coordinate = cachedGridCoordinate(child); | |
| 1085 const GridSpan& span = (direction == ForColumns) ? coordinate.columns : coor
dinate.rows; | |
| 1086 LayoutUnit gridAreaBreadth = 0; | |
| 1087 for (GridSpan::iterator trackPosition = span.begin(); trackPosition != span.
end(); ++trackPosition) | |
| 1088 gridAreaBreadth += tracks[trackPosition.toInt()].m_usedBreadth; | |
| 1089 return gridAreaBreadth; | |
| 1090 } | |
| 1091 | |
| 1092 void RenderGrid::populateGridPositions(const GridSizingData& sizingData) | |
| 1093 { | |
| 1094 m_columnPositions.resize(sizingData.columnTracks.size() + 1); | |
| 1095 m_columnPositions[0] = borderAndPaddingStart(); | |
| 1096 for (size_t i = 0; i < m_columnPositions.size() - 1; ++i) | |
| 1097 m_columnPositions[i + 1] = m_columnPositions[i] + sizingData.columnTrack
s[i].m_usedBreadth; | |
| 1098 | |
| 1099 m_rowPositions.resize(sizingData.rowTracks.size() + 1); | |
| 1100 m_rowPositions[0] = borderAndPaddingBefore(); | |
| 1101 for (size_t i = 0; i < m_rowPositions.size() - 1; ++i) | |
| 1102 m_rowPositions[i + 1] = m_rowPositions[i] + sizingData.rowTracks[i].m_us
edBreadth; | |
| 1103 } | |
| 1104 | |
| 1105 LayoutUnit RenderGrid::startOfColumnForChild(const RenderBox* child) const | |
| 1106 { | |
| 1107 const GridCoordinate& coordinate = cachedGridCoordinate(child); | |
| 1108 LayoutUnit startOfColumn = m_columnPositions[coordinate.columns.resolvedInit
ialPosition.toInt()]; | |
| 1109 // The grid items should be inside the grid container's border box, that's w
hy they need to be shifted. | |
| 1110 // FIXME: This should account for the grid item's <overflow-position>. | |
| 1111 return startOfColumn + marginStartForChild(child); | |
| 1112 } | |
| 1113 | |
| 1114 LayoutUnit RenderGrid::endOfColumnForChild(const RenderBox* child) const | |
| 1115 { | |
| 1116 const GridCoordinate& coordinate = cachedGridCoordinate(child); | |
| 1117 LayoutUnit startOfColumn = m_columnPositions[coordinate.columns.resolvedInit
ialPosition.toInt()]; | |
| 1118 // The grid items should be inside the grid container's border box, that's w
hy they need to be shifted. | |
| 1119 LayoutUnit columnPosition = startOfColumn + marginStartForChild(child); | |
| 1120 | |
| 1121 LayoutUnit endOfColumn = m_columnPositions[coordinate.columns.resolvedFinalP
osition.next().toInt()]; | |
| 1122 // FIXME: This should account for the grid item's <overflow-position>. | |
| 1123 return columnPosition + std::max<LayoutUnit>(0, endOfColumn - m_columnPositi
ons[coordinate.columns.resolvedInitialPosition.toInt()] - child->logicalWidth())
; | |
| 1124 } | |
| 1125 | |
| 1126 LayoutUnit RenderGrid::columnPositionAlignedWithGridContainerStart(const RenderB
ox* child) const | |
| 1127 { | |
| 1128 if (style()->isLeftToRightDirection()) | |
| 1129 return startOfColumnForChild(child); | |
| 1130 | |
| 1131 return endOfColumnForChild(child); | |
| 1132 } | |
| 1133 | |
| 1134 LayoutUnit RenderGrid::columnPositionAlignedWithGridContainerEnd(const RenderBox
* child) const | |
| 1135 { | |
| 1136 if (!style()->isLeftToRightDirection()) | |
| 1137 return startOfColumnForChild(child); | |
| 1138 | |
| 1139 return endOfColumnForChild(child); | |
| 1140 } | |
| 1141 | |
| 1142 LayoutUnit RenderGrid::centeredColumnPositionForChild(const RenderBox* child) co
nst | |
| 1143 { | |
| 1144 const GridCoordinate& coordinate = cachedGridCoordinate(child); | |
| 1145 LayoutUnit startOfColumn = m_columnPositions[coordinate.columns.resolvedInit
ialPosition.toInt()]; | |
| 1146 LayoutUnit endOfColumn = m_columnPositions[coordinate.columns.resolvedFinalP
osition.next().toInt()]; | |
| 1147 LayoutUnit columnPosition = startOfColumn + marginStartForChild(child); | |
| 1148 // FIXME: This should account for the grid item's <overflow-position>. | |
| 1149 return columnPosition + std::max<LayoutUnit>(0, endOfColumn - startOfColumn
- child->logicalWidth()) / 2; | |
| 1150 } | |
| 1151 | |
| 1152 static ItemPosition resolveJustification(const RenderStyle* parentStyle, const R
enderStyle* childStyle) | |
| 1153 { | |
| 1154 ItemPosition justify = childStyle->justifySelf(); | |
| 1155 if (justify == ItemPositionAuto) | |
| 1156 justify = (parentStyle->justifyItems() == ItemPositionAuto) ? ItemPositi
onStretch : parentStyle->justifyItems(); | |
| 1157 | |
| 1158 return justify; | |
| 1159 } | |
| 1160 | |
| 1161 LayoutUnit RenderGrid::columnPositionForChild(const RenderBox* child) const | |
| 1162 { | |
| 1163 switch (resolveJustification(style(), child->style())) { | |
| 1164 case ItemPositionSelfStart: | |
| 1165 // self-start is based on the child's direction. That's why we need to c
heck against the grid container's direction. | |
| 1166 if (child->style()->direction() != style()->direction()) | |
| 1167 return columnPositionAlignedWithGridContainerEnd(child); | |
| 1168 | |
| 1169 return columnPositionAlignedWithGridContainerStart(child); | |
| 1170 case ItemPositionSelfEnd: | |
| 1171 // self-end is based on the child's direction. That's why we need to che
ck against the grid container's direction. | |
| 1172 if (child->style()->direction() != style()->direction()) | |
| 1173 return columnPositionAlignedWithGridContainerStart(child); | |
| 1174 | |
| 1175 return columnPositionAlignedWithGridContainerEnd(child); | |
| 1176 | |
| 1177 case ItemPositionFlexStart: | |
| 1178 // Only used in flex layout, for other layout, it's equivalent to 'start
'. | |
| 1179 return columnPositionAlignedWithGridContainerStart(child); | |
| 1180 case ItemPositionFlexEnd: | |
| 1181 // Only used in flex layout, for other layout, it's equivalent to 'start
'. | |
| 1182 return columnPositionAlignedWithGridContainerEnd(child); | |
| 1183 | |
| 1184 case ItemPositionLeft: | |
| 1185 if (style()->isLeftToRightDirection()) | |
| 1186 return columnPositionAlignedWithGridContainerStart(child); | |
| 1187 | |
| 1188 return columnPositionAlignedWithGridContainerEnd(child); | |
| 1189 case ItemPositionRight: | |
| 1190 if (style()->isLeftToRightDirection()) | |
| 1191 return columnPositionAlignedWithGridContainerEnd(child); | |
| 1192 | |
| 1193 return columnPositionAlignedWithGridContainerStart(child); | |
| 1194 | |
| 1195 case ItemPositionCenter: | |
| 1196 return centeredColumnPositionForChild(child); | |
| 1197 case ItemPositionStart: | |
| 1198 return columnPositionAlignedWithGridContainerStart(child); | |
| 1199 case ItemPositionEnd: | |
| 1200 return columnPositionAlignedWithGridContainerEnd(child); | |
| 1201 | |
| 1202 case ItemPositionAuto: | |
| 1203 break; | |
| 1204 case ItemPositionStretch: | |
| 1205 case ItemPositionBaseline: | |
| 1206 case ItemPositionLastBaseline: | |
| 1207 // FIXME: Implement the previous values. For now, we always start align
the child. | |
| 1208 return startOfColumnForChild(child); | |
| 1209 } | |
| 1210 | |
| 1211 ASSERT_NOT_REACHED(); | |
| 1212 return 0; | |
| 1213 } | |
| 1214 | |
| 1215 LayoutUnit RenderGrid::endOfRowForChild(const RenderBox* child) const | |
| 1216 { | |
| 1217 const GridCoordinate& coordinate = cachedGridCoordinate(child); | |
| 1218 | |
| 1219 LayoutUnit startOfRow = m_rowPositions[coordinate.rows.resolvedInitialPositi
on.toInt()]; | |
| 1220 // The grid items should be inside the grid container's border box, that's w
hy they need to be shifted. | |
| 1221 LayoutUnit rowPosition = startOfRow + marginBeforeForChild(child); | |
| 1222 | |
| 1223 LayoutUnit endOfRow = m_rowPositions[coordinate.rows.resolvedFinalPosition.n
ext().toInt()]; | |
| 1224 // FIXME: This should account for the grid item's <overflow-position>. | |
| 1225 return rowPosition + std::max<LayoutUnit>(0, endOfRow - startOfRow - child->
logicalHeight()); | |
| 1226 } | |
| 1227 | |
| 1228 LayoutUnit RenderGrid::startOfRowForChild(const RenderBox* child) const | |
| 1229 { | |
| 1230 const GridCoordinate& coordinate = cachedGridCoordinate(child); | |
| 1231 | |
| 1232 LayoutUnit startOfRow = m_rowPositions[coordinate.rows.resolvedInitialPositi
on.toInt()]; | |
| 1233 // The grid items should be inside the grid container's border box, that's w
hy they need to be shifted. | |
| 1234 // FIXME: This should account for the grid item's <overflow-position>. | |
| 1235 LayoutUnit rowPosition = startOfRow + marginBeforeForChild(child); | |
| 1236 | |
| 1237 return rowPosition; | |
| 1238 } | |
| 1239 | |
| 1240 LayoutUnit RenderGrid::centeredRowPositionForChild(const RenderBox* child) const | |
| 1241 { | |
| 1242 const GridCoordinate& coordinate = cachedGridCoordinate(child); | |
| 1243 | |
| 1244 // The grid items should be inside the grid container's border box, that's w
hy they need to be shifted. | |
| 1245 LayoutUnit startOfRow = m_rowPositions[coordinate.rows.resolvedInitialPositi
on.toInt()] + marginBeforeForChild(child); | |
| 1246 LayoutUnit endOfRow = m_rowPositions[coordinate.rows.resolvedFinalPosition.n
ext().toInt()]; | |
| 1247 | |
| 1248 // FIXME: This should account for the grid item's <overflow-position>. | |
| 1249 return startOfRow + std::max<LayoutUnit>(0, endOfRow - startOfRow - child->l
ogicalHeight()) / 2; | |
| 1250 } | |
| 1251 | |
| 1252 // FIXME: We should move this logic to the StyleAdjuster or the StyleBuilder. | |
| 1253 static ItemPosition resolveAlignment(const RenderStyle* parentStyle, const Rende
rStyle* childStyle) | |
| 1254 { | |
| 1255 ItemPosition align = childStyle->alignSelf(); | |
| 1256 // The auto keyword computes to the parent's align-items computed value, or
to "stretch", if not set or "auto". | |
| 1257 if (align == ItemPositionAuto) | |
| 1258 align = (parentStyle->alignItems() == ItemPositionAuto) ? ItemPositionSt
retch : parentStyle->alignItems(); | |
| 1259 return align; | |
| 1260 } | |
| 1261 | |
| 1262 LayoutUnit RenderGrid::rowPositionForChild(const RenderBox* child) const | |
| 1263 { | |
| 1264 ItemPosition alignSelf = resolveAlignment(style(), child->style()); | |
| 1265 | |
| 1266 switch (alignSelf) { | |
| 1267 case ItemPositionSelfStart: | |
| 1268 return startOfRowForChild(child); | |
| 1269 case ItemPositionSelfEnd: | |
| 1270 return endOfRowForChild(child); | |
| 1271 | |
| 1272 case ItemPositionLeft: | |
| 1273 // orthogonal modes make property and inline axes to be parallel, but in
any case | |
| 1274 // this is always equivalent to 'Start'. | |
| 1275 // | |
| 1276 // self-align's axis is never parallel to the inline axis, except in ort
hogonal | |
| 1277 // writing-mode, so this is equivalent to 'Start’. | |
| 1278 return startOfRowForChild(child); | |
| 1279 | |
| 1280 case ItemPositionRight: | |
| 1281 // self-align's axis is never parallel to the inline axis, except in ort
hogonal | |
| 1282 // writing-mode, so this is equivalent to 'Start'. | |
| 1283 return startOfRowForChild(child); | |
| 1284 | |
| 1285 case ItemPositionCenter: | |
| 1286 return centeredRowPositionForChild(child); | |
| 1287 // Only used in flex layout, for other layout, it's equivalent to 'Start
'. | |
| 1288 case ItemPositionFlexStart: | |
| 1289 case ItemPositionStart: | |
| 1290 return startOfRowForChild(child); | |
| 1291 // Only used in flex layout, for other layout, it's equivalent to 'End'. | |
| 1292 case ItemPositionFlexEnd: | |
| 1293 case ItemPositionEnd: | |
| 1294 return endOfRowForChild(child); | |
| 1295 case ItemPositionStretch: | |
| 1296 // FIXME: Implement the Stretch value. For now, we always start align th
e child. | |
| 1297 return startOfRowForChild(child); | |
| 1298 case ItemPositionBaseline: | |
| 1299 case ItemPositionLastBaseline: | |
| 1300 // FIXME: Implement the ItemPositionBaseline value. For now, we always s
tart align the child. | |
| 1301 return startOfRowForChild(child); | |
| 1302 case ItemPositionAuto: | |
| 1303 break; | |
| 1304 } | |
| 1305 | |
| 1306 ASSERT_NOT_REACHED(); | |
| 1307 return 0; | |
| 1308 } | |
| 1309 | |
| 1310 LayoutPoint RenderGrid::findChildLogicalPosition(const RenderBox* child) const | |
| 1311 { | |
| 1312 return LayoutPoint(columnPositionForChild(child), rowPositionForChild(child)
); | |
| 1313 } | |
| 1314 | |
| 1315 static GridSpan dirtiedGridAreas(const Vector<LayoutUnit>& coordinates, LayoutUn
it start, LayoutUnit end) | |
| 1316 { | |
| 1317 // This function does a binary search over the coordinates. | |
| 1318 // This doesn't work with grid items overflowing their grid areas, but that
is managed with m_gridItemsOverflowingGridArea. | |
| 1319 | |
| 1320 size_t startGridAreaIndex = std::upper_bound(coordinates.begin(), coordinate
s.end() - 1, start) - coordinates.begin(); | |
| 1321 if (startGridAreaIndex > 0) | |
| 1322 --startGridAreaIndex; | |
| 1323 | |
| 1324 size_t endGridAreaIndex = std::upper_bound(coordinates.begin() + startGridAr
eaIndex, coordinates.end() - 1, end) - coordinates.begin(); | |
| 1325 if (endGridAreaIndex > 0) | |
| 1326 --endGridAreaIndex; | |
| 1327 | |
| 1328 return GridSpan(startGridAreaIndex, endGridAreaIndex); | |
| 1329 } | |
| 1330 | |
| 1331 class GridItemsSorter { | |
| 1332 public: | |
| 1333 bool operator()(const std::pair<RenderBox*, size_t>& firstChild, const std::
pair<RenderBox*, size_t>& secondChild) const | |
| 1334 { | |
| 1335 if (firstChild.first->style()->order() != secondChild.first->style()->or
der()) | |
| 1336 return firstChild.first->style()->order() < secondChild.first->style
()->order(); | |
| 1337 | |
| 1338 return firstChild.second < secondChild.second; | |
| 1339 } | |
| 1340 }; | |
| 1341 | |
| 1342 void RenderGrid::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOff
set) | |
| 1343 { | |
| 1344 ASSERT_WITH_SECURITY_IMPLICATION(!gridIsDirty()); | |
| 1345 | |
| 1346 LayoutRect localPaintInvalidationRect = paintInfo.rect; | |
| 1347 localPaintInvalidationRect.moveBy(-paintOffset); | |
| 1348 | |
| 1349 GridSpan dirtiedColumns = dirtiedGridAreas(m_columnPositions, localPaintInva
lidationRect.x(), localPaintInvalidationRect.maxX()); | |
| 1350 GridSpan dirtiedRows = dirtiedGridAreas(m_rowPositions, localPaintInvalidati
onRect.y(), localPaintInvalidationRect.maxY()); | |
| 1351 | |
| 1352 Vector<std::pair<RenderBox*, size_t> > gridItemsToBePainted; | |
| 1353 | |
| 1354 for (GridSpan::iterator row = dirtiedRows.begin(); row != dirtiedRows.end();
++row) { | |
| 1355 for (GridSpan::iterator column = dirtiedColumns.begin(); column != dirti
edColumns.end(); ++column) { | |
| 1356 const Vector<RenderBox*, 1>& children = m_grid[row.toInt()][column.t
oInt()]; | |
| 1357 for (size_t j = 0; j < children.size(); ++j) | |
| 1358 gridItemsToBePainted.append(std::make_pair(children[j], m_gridIt
emsIndexesMap.get(children[j]))); | |
| 1359 } | |
| 1360 } | |
| 1361 | |
| 1362 for (Vector<RenderBox*>::const_iterator it = m_gridItemsOverflowingGridArea.
begin(); it != m_gridItemsOverflowingGridArea.end(); ++it) { | |
| 1363 if ((*it)->frameRect().intersects(localPaintInvalidationRect)) | |
| 1364 gridItemsToBePainted.append(std::make_pair(*it, m_gridItemsIndexesMa
p.get(*it))); | |
| 1365 } | |
| 1366 | |
| 1367 // Sort grid items following order-modified document order. | |
| 1368 // See http://www.w3.org/TR/css-flexbox/#order-modified-document-order | |
| 1369 std::stable_sort(gridItemsToBePainted.begin(), gridItemsToBePainted.end(), G
ridItemsSorter()); | |
| 1370 | |
| 1371 RenderBox* previous = 0; | |
| 1372 for (Vector<std::pair<RenderBox*, size_t> >::const_iterator it = gridItemsTo
BePainted.begin(); it != gridItemsToBePainted.end(); ++it) { | |
| 1373 // We might have duplicates because of spanning children are included in
all cells they span. | |
| 1374 // Skip them here to avoid painting items several times. | |
| 1375 RenderBox* current = (*it).first; | |
| 1376 if (current == previous) | |
| 1377 continue; | |
| 1378 | |
| 1379 paintChild(current, paintInfo, paintOffset); | |
| 1380 previous = current; | |
| 1381 } | |
| 1382 } | |
| 1383 | |
| 1384 const char* RenderGrid::renderName() const | |
| 1385 { | |
| 1386 if (isFloating()) | |
| 1387 return "RenderGrid (floating)"; | |
| 1388 if (isOutOfFlowPositioned()) | |
| 1389 return "RenderGrid (positioned)"; | |
| 1390 if (isAnonymous()) | |
| 1391 return "RenderGrid (generated)"; | |
| 1392 if (isRelPositioned()) | |
| 1393 return "RenderGrid (relative positioned)"; | |
| 1394 return "RenderGrid"; | |
| 1395 } | |
| 1396 | |
| 1397 } // namespace blink | |
| OLD | NEW |