• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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