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