Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(23)

Side by Side Diff: Source/core/rendering/RenderGrid.cpp

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

Powered by Google App Engine
This is Rietveld 408576698