2 * Copyright (C) 2011 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "core/layout/LayoutGrid.h"
29 #include "core/layout/LayoutView.h"
30 #include "core/layout/TextAutosizer.h"
31 #include "core/paint/DeprecatedPaintLayer.h"
32 #include "core/paint/GridPainter.h"
33 #include "core/style/ComputedStyle.h"
34 #include "core/style/GridCoordinate.h"
35 #include "platform/LengthFunctions.h"
39 static const int infinity
= -1;
41 class GridItemWithSpan
;
49 , m_sizeDuringDistribution(0)
50 , m_infinitelyGrowable(false)
54 const LayoutUnit
& baseSize() const
56 ASSERT(isGrowthLimitBiggerThanBaseSize());
60 const LayoutUnit
& growthLimit() const
62 ASSERT(isGrowthLimitBiggerThanBaseSize());
66 void setBaseSize(LayoutUnit baseSize
)
68 m_baseSize
= baseSize
;
69 ensureGrowthLimitIsBiggerThanBaseSize();
72 void setGrowthLimit(LayoutUnit growthLimit
)
74 m_growthLimit
= growthLimit
;
75 ensureGrowthLimitIsBiggerThanBaseSize();
78 bool growthLimitIsInfinite() const
80 return m_growthLimit
== infinity
;
83 bool infiniteGrowthPotential() const
85 return growthLimitIsInfinite() || m_infinitelyGrowable
;
88 const LayoutUnit
& plannedSize() const { return m_plannedSize
; }
90 void setPlannedSize(const LayoutUnit
& plannedSize
)
92 ASSERT(plannedSize
>= 0 || plannedSize
== infinity
);
93 m_plannedSize
= plannedSize
;
96 const LayoutUnit
& sizeDuringDistribution() { return m_sizeDuringDistribution
; }
98 void setSizeDuringDistribution(const LayoutUnit
& sizeDuringDistribution
)
100 ASSERT(sizeDuringDistribution
>= 0);
101 m_sizeDuringDistribution
= sizeDuringDistribution
;
104 void growSizeDuringDistribution(const LayoutUnit
& sizeDuringDistribution
)
106 ASSERT(sizeDuringDistribution
>= 0);
107 m_sizeDuringDistribution
+= sizeDuringDistribution
;
110 bool infinitelyGrowable() const { return m_infinitelyGrowable
; }
111 void setInfinitelyGrowable(bool infinitelyGrowable
) { m_infinitelyGrowable
= infinitelyGrowable
; }
114 bool isGrowthLimitBiggerThanBaseSize() const { return growthLimitIsInfinite() || m_growthLimit
>= m_baseSize
; }
116 void ensureGrowthLimitIsBiggerThanBaseSize()
118 if (m_growthLimit
!= infinity
&& m_growthLimit
< m_baseSize
)
119 m_growthLimit
= m_baseSize
;
122 LayoutUnit m_baseSize
;
123 LayoutUnit m_growthLimit
;
124 LayoutUnit m_plannedSize
;
125 LayoutUnit m_sizeDuringDistribution
;
126 bool m_infinitelyGrowable
;
129 struct ContentAlignmentData
{
132 ContentAlignmentData() {};
133 ContentAlignmentData(LayoutUnit position
, LayoutUnit distribution
)
134 : positionOffset(position
)
135 , distributionOffset(distribution
)
139 bool isValid() { return positionOffset
>= 0 && distributionOffset
>= 0; }
141 LayoutUnit positionOffset
= -1;
142 LayoutUnit distributionOffset
= -1;
145 struct GridTrackForNormalization
{
146 GridTrackForNormalization(const GridTrack
& track
, double flex
)
149 , m_normalizedFlexValue(track
.baseSize() / flex
)
153 // Required by std::sort.
154 GridTrackForNormalization
& operator=(const GridTrackForNormalization
& o
)
158 m_normalizedFlexValue
= o
.m_normalizedFlexValue
;
162 const GridTrack
* m_track
;
164 LayoutUnit m_normalizedFlexValue
;
167 enum TrackSizeRestriction
{
172 class LayoutGrid::GridIterator
{
173 WTF_MAKE_NONCOPYABLE(GridIterator
);
175 // |direction| is the direction that is fixed to |fixedTrackIndex| so e.g
176 // GridIterator(m_grid, ForColumns, 1) will walk over the rows of the 2nd column.
177 GridIterator(const GridRepresentation
& grid
, GridTrackSizingDirection direction
, size_t fixedTrackIndex
, size_t varyingTrackIndex
= 0)
179 , m_direction(direction
)
180 , m_rowIndex((direction
== ForColumns
) ? varyingTrackIndex
: fixedTrackIndex
)
181 , m_columnIndex((direction
== ForColumns
) ? fixedTrackIndex
: varyingTrackIndex
)
184 ASSERT(m_rowIndex
< m_grid
.size());
185 ASSERT(m_columnIndex
< m_grid
[0].size());
188 LayoutBox
* nextGridItem()
190 ASSERT(!m_grid
.isEmpty());
192 size_t& varyingTrackIndex
= (m_direction
== ForColumns
) ? m_rowIndex
: m_columnIndex
;
193 const size_t endOfVaryingTrackIndex
= (m_direction
== ForColumns
) ? m_grid
.size() : m_grid
[0].size();
194 for (; varyingTrackIndex
< endOfVaryingTrackIndex
; ++varyingTrackIndex
) {
195 const GridCell
& children
= m_grid
[m_rowIndex
][m_columnIndex
];
196 if (m_childIndex
< children
.size())
197 return children
[m_childIndex
++];
204 bool checkEmptyCells(size_t rowSpan
, size_t columnSpan
) const
206 // Ignore cells outside current grid as we will grow it later if needed.
207 size_t maxRows
= std::min(m_rowIndex
+ rowSpan
, m_grid
.size());
208 size_t maxColumns
= std::min(m_columnIndex
+ columnSpan
, m_grid
[0].size());
210 // This adds a O(N^2) behavior that shouldn't be a big deal as we expect spanning areas to be small.
211 for (size_t row
= m_rowIndex
; row
< maxRows
; ++row
) {
212 for (size_t column
= m_columnIndex
; column
< maxColumns
; ++column
) {
213 const GridCell
& children
= m_grid
[row
][column
];
214 if (!children
.isEmpty())
222 PassOwnPtr
<GridCoordinate
> nextEmptyGridArea(size_t fixedTrackSpan
, size_t varyingTrackSpan
)
224 ASSERT(!m_grid
.isEmpty());
225 ASSERT(fixedTrackSpan
>= 1 && varyingTrackSpan
>= 1);
227 size_t rowSpan
= (m_direction
== ForColumns
) ? varyingTrackSpan
: fixedTrackSpan
;
228 size_t columnSpan
= (m_direction
== ForColumns
) ? fixedTrackSpan
: varyingTrackSpan
;
230 size_t& varyingTrackIndex
= (m_direction
== ForColumns
) ? m_rowIndex
: m_columnIndex
;
231 const size_t endOfVaryingTrackIndex
= (m_direction
== ForColumns
) ? m_grid
.size() : m_grid
[0].size();
232 for (; varyingTrackIndex
< endOfVaryingTrackIndex
; ++varyingTrackIndex
) {
233 if (checkEmptyCells(rowSpan
, columnSpan
)) {
234 OwnPtr
<GridCoordinate
> result
= adoptPtr(new GridCoordinate(GridSpan(m_rowIndex
, m_rowIndex
+ rowSpan
- 1), GridSpan(m_columnIndex
, m_columnIndex
+ columnSpan
- 1)));
235 // Advance the iterator to avoid an infinite loop where we would return the same grid area over and over.
237 return result
.release();
244 const GridRepresentation
& m_grid
;
245 GridTrackSizingDirection m_direction
;
247 size_t m_columnIndex
;
251 struct LayoutGrid::GridSizingData
{
252 WTF_MAKE_NONCOPYABLE(GridSizingData
);
255 GridSizingData(size_t gridColumnCount
, size_t gridRowCount
)
256 : columnTracks(gridColumnCount
)
257 , rowTracks(gridRowCount
)
261 Vector
<GridTrack
> columnTracks
;
262 Vector
<GridTrack
> rowTracks
;
263 Vector
<size_t> contentSizedTracksIndex
;
265 // Performance optimization: hold onto these Vectors until the end of Layout to avoid repeated malloc / free.
266 Vector
<GridTrack
*> filteredTracks
;
267 Vector
<GridItemWithSpan
> itemsSortedByIncreasingSpan
;
268 Vector
<GridTrack
*> growBeyondGrowthLimitsTracks
;
271 struct GridItemsSpanGroupRange
{
272 Vector
<GridItemWithSpan
>::iterator rangeStart
;
273 Vector
<GridItemWithSpan
>::iterator rangeEnd
;
276 LayoutGrid::LayoutGrid(Element
* element
)
277 : LayoutBlock(element
)
278 , m_gridIsDirty(true)
279 , m_orderIterator(this)
281 ASSERT(!childrenInline());
284 LayoutGrid::~LayoutGrid()
288 void LayoutGrid::addChild(LayoutObject
* newChild
, LayoutObject
* beforeChild
)
290 LayoutBlock::addChild(newChild
, beforeChild
);
292 // The grid needs to be recomputed as it might contain auto-placed items that will change their position.
296 void LayoutGrid::removeChild(LayoutObject
* child
)
298 LayoutBlock::removeChild(child
);
300 // The grid needs to be recomputed as it might contain auto-placed items that will change their position.
304 void LayoutGrid::styleDidChange(StyleDifference diff
, const ComputedStyle
* oldStyle
)
306 LayoutBlock::styleDidChange(diff
, oldStyle
);
310 // FIXME: The following checks could be narrowed down if we kept track of which type of grid items we have:
311 // - explicit grid size changes impact negative explicitely positioned and auto-placed grid items.
312 // - named grid lines only impact grid items with named grid lines.
313 // - auto-flow changes only impacts auto-placed children.
315 if (explicitGridDidResize(*oldStyle
)
316 || namedGridLinesDefinitionDidChange(*oldStyle
)
317 || oldStyle
->gridAutoFlow() != styleRef().gridAutoFlow())
321 bool LayoutGrid::explicitGridDidResize(const ComputedStyle
& oldStyle
) const
323 return oldStyle
.gridTemplateColumns().size() != styleRef().gridTemplateColumns().size()
324 || oldStyle
.gridTemplateRows().size() != styleRef().gridTemplateRows().size();
327 bool LayoutGrid::namedGridLinesDefinitionDidChange(const ComputedStyle
& oldStyle
) const
329 return oldStyle
.namedGridRowLines() != styleRef().namedGridRowLines()
330 || oldStyle
.namedGridColumnLines() != styleRef().namedGridColumnLines();
333 void LayoutGrid::layoutBlock(bool relayoutChildren
)
335 ASSERT(needsLayout());
337 if (!relayoutChildren
&& simplifiedLayout())
340 // FIXME: Much of this method is boiler plate that matches LayoutBox::layoutBlock and Layout*FlexibleBox::layoutBlock.
341 // It would be nice to refactor some of the duplicate code.
343 // LayoutState needs this deliberate scope to pop before updating scroll information (which
344 // may trigger relayout).
345 LayoutState
state(*this, locationOffset());
347 LayoutSize previousSize
= size();
350 updateLogicalWidth();
352 TextAutosizer::LayoutScope
textAutosizerLayoutScope(this);
356 LayoutUnit oldClientAfterEdge
= clientLogicalBottom();
357 updateLogicalHeight();
359 if (size() != previousSize
)
360 relayoutChildren
= true;
362 layoutPositionedObjects(relayoutChildren
|| isDocumentElement());
364 computeOverflow(oldClientAfterEdge
);
367 updateLayerTransformAfterLayout();
368 updateScrollInfoAfterLayout();
373 void LayoutGrid::computeIntrinsicLogicalWidths(LayoutUnit
& minLogicalWidth
, LayoutUnit
& maxLogicalWidth
) const
375 const_cast<LayoutGrid
*>(this)->placeItemsOnGrid();
377 GridSizingData
sizingData(gridColumnCount(), gridRowCount());
378 LayoutUnit availableLogicalSpace
= 0;
379 const_cast<LayoutGrid
*>(this)->computeUsedBreadthOfGridTracks(ForColumns
, sizingData
, availableLogicalSpace
);
381 for (const auto& column
: sizingData
.columnTracks
) {
382 const LayoutUnit
& minTrackBreadth
= column
.baseSize();
383 const LayoutUnit
& maxTrackBreadth
= column
.growthLimit();
385 minLogicalWidth
+= minTrackBreadth
;
386 maxLogicalWidth
+= maxTrackBreadth
;
389 LayoutUnit scrollbarWidth
= intrinsicScrollbarLogicalWidth();
390 minLogicalWidth
+= scrollbarWidth
;
391 maxLogicalWidth
+= scrollbarWidth
;
394 bool LayoutGrid::gridElementIsShrinkToFit()
396 return isFloatingOrOutOfFlowPositioned();
399 void LayoutGrid::computeUsedBreadthOfGridTracks(GridTrackSizingDirection direction
, GridSizingData
& sizingData
, LayoutUnit
& freeSpace
)
401 const LayoutUnit initialFreeSpace
= freeSpace
;
402 Vector
<GridTrack
>& tracks
= (direction
== ForColumns
) ? sizingData
.columnTracks
: sizingData
.rowTracks
;
403 Vector
<size_t> flexibleSizedTracksIndex
;
404 sizingData
.contentSizedTracksIndex
.shrink(0);
406 // 1. Initialize per Grid track variables.
407 for (size_t i
= 0; i
< tracks
.size(); ++i
) {
408 GridTrack
& track
= tracks
[i
];
409 GridTrackSize trackSize
= gridTrackSize(direction
, i
);
410 const GridLength
& minTrackBreadth
= trackSize
.minTrackBreadth();
411 const GridLength
& maxTrackBreadth
= trackSize
.maxTrackBreadth();
413 track
.setBaseSize(computeUsedBreadthOfMinLength(direction
, minTrackBreadth
));
414 track
.setGrowthLimit(computeUsedBreadthOfMaxLength(direction
, maxTrackBreadth
, track
.baseSize()));
415 track
.setInfinitelyGrowable(false);
417 if (trackSize
.isContentSized())
418 sizingData
.contentSizedTracksIndex
.append(i
);
419 if (trackSize
.maxTrackBreadth().isFlex())
420 flexibleSizedTracksIndex
.append(i
);
423 // 2. Resolve content-based TrackSizingFunctions.
424 if (!sizingData
.contentSizedTracksIndex
.isEmpty())
425 resolveContentBasedTrackSizingFunctions(direction
, sizingData
);
427 for (const auto& track
: tracks
) {
428 ASSERT(!track
.infiniteGrowthPotential());
429 freeSpace
-= track
.baseSize();
432 const bool hasUndefinedRemainingSpace
= (direction
== ForRows
) ? style()->logicalHeight().isAuto() : gridElementIsShrinkToFit();
434 if (!hasUndefinedRemainingSpace
&& freeSpace
<= 0)
437 // 3. Grow all Grid tracks in GridTracks from their baseSize up to their growthLimit value until freeSpace is exhausted.
438 const size_t tracksSize
= tracks
.size();
439 if (!hasUndefinedRemainingSpace
) {
440 Vector
<GridTrack
*> tracksForDistribution(tracksSize
);
441 for (size_t i
= 0; i
< tracksSize
; ++i
) {
442 tracksForDistribution
[i
] = tracks
.data() + i
;
443 tracksForDistribution
[i
]->setPlannedSize(tracksForDistribution
[i
]->baseSize());
446 distributeSpaceToTracks
<MaximizeTracks
>(tracksForDistribution
, nullptr, sizingData
, freeSpace
);
448 for (auto* track
: tracksForDistribution
)
449 track
->setBaseSize(track
->plannedSize());
451 for (auto& track
: tracks
)
452 track
.setBaseSize(track
.growthLimit());
455 if (flexibleSizedTracksIndex
.isEmpty())
458 // 4. Grow all Grid tracks having a fraction as the MaxTrackSizingFunction.
459 double normalizedFractionBreadth
= 0;
460 if (!hasUndefinedRemainingSpace
) {
461 normalizedFractionBreadth
= computeNormalizedFractionBreadth(tracks
, GridSpan(0, tracks
.size() - 1), direction
, initialFreeSpace
);
463 for (const auto& trackIndex
: flexibleSizedTracksIndex
) {
464 GridTrackSize trackSize
= gridTrackSize(direction
, trackIndex
);
465 normalizedFractionBreadth
= std::max(normalizedFractionBreadth
, tracks
[trackIndex
].baseSize() / trackSize
.maxTrackBreadth().flex());
468 for (size_t i
= 0; i
< flexibleSizedTracksIndex
.size(); ++i
) {
469 GridIterator
iterator(m_grid
, direction
, flexibleSizedTracksIndex
[i
]);
470 while (LayoutBox
* gridItem
= iterator
.nextGridItem()) {
471 const GridCoordinate coordinate
= cachedGridCoordinate(*gridItem
);
472 const GridSpan span
= (direction
== ForColumns
) ? coordinate
.columns
: coordinate
.rows
;
474 // Do not include already processed items.
475 if (i
> 0 && span
.resolvedInitialPosition
.toInt() <= flexibleSizedTracksIndex
[i
- 1])
478 double itemNormalizedFlexBreadth
= computeNormalizedFractionBreadth(tracks
, span
, direction
, maxContentForChild(*gridItem
, direction
, sizingData
.columnTracks
));
479 normalizedFractionBreadth
= std::max(normalizedFractionBreadth
, itemNormalizedFlexBreadth
);
484 for (const auto& trackIndex
: flexibleSizedTracksIndex
) {
485 GridTrackSize trackSize
= gridTrackSize(direction
, trackIndex
);
487 LayoutUnit baseSize
= std::max
<LayoutUnit
>(tracks
[trackIndex
].baseSize(), normalizedFractionBreadth
* trackSize
.maxTrackBreadth().flex());
488 tracks
[trackIndex
].setBaseSize(baseSize
);
489 freeSpace
-= baseSize
;
492 // FIXME: Should ASSERT flexible tracks exhaust the freeSpace ? (see issue 739613002).
495 LayoutUnit
LayoutGrid::computeUsedBreadthOfMinLength(GridTrackSizingDirection direction
, const GridLength
& gridLength
) const
497 if (gridLength
.isFlex())
500 const Length
& trackLength
= gridLength
.length();
501 if (trackLength
.isSpecified())
502 return computeUsedBreadthOfSpecifiedLength(direction
, trackLength
);
504 ASSERT(trackLength
.isMinContent() || trackLength
.isAuto() || trackLength
.isMaxContent());
508 LayoutUnit
LayoutGrid::computeUsedBreadthOfMaxLength(GridTrackSizingDirection direction
, const GridLength
& gridLength
, LayoutUnit usedBreadth
) const
510 if (gridLength
.isFlex())
513 const Length
& trackLength
= gridLength
.length();
514 if (trackLength
.isSpecified()) {
515 LayoutUnit computedBreadth
= computeUsedBreadthOfSpecifiedLength(direction
, trackLength
);
516 ASSERT(computedBreadth
!= infinity
);
517 return computedBreadth
;
520 ASSERT(trackLength
.isMinContent() || trackLength
.isAuto() || trackLength
.isMaxContent());
524 LayoutUnit
LayoutGrid::computeUsedBreadthOfSpecifiedLength(GridTrackSizingDirection direction
, const Length
& trackLength
) const
526 ASSERT(trackLength
.isSpecified());
527 // FIXME: The -1 here should be replaced by whatever the intrinsic height of the grid is.
528 return valueForLength(trackLength
, direction
== ForColumns
? contentLogicalWidth() : std::max(LayoutUnit(), computeContentLogicalHeight(MainOrPreferredSize
, style()->logicalHeight(), -1)));
531 static bool sortByGridNormalizedFlexValue(const GridTrackForNormalization
& track1
, const GridTrackForNormalization
& track2
)
533 return track1
.m_normalizedFlexValue
< track2
.m_normalizedFlexValue
;
536 double LayoutGrid::computeNormalizedFractionBreadth(Vector
<GridTrack
>& tracks
, const GridSpan
& tracksSpan
, GridTrackSizingDirection direction
, LayoutUnit spaceToFill
) const
538 LayoutUnit allocatedSpace
;
539 Vector
<GridTrackForNormalization
> tracksForNormalization
;
540 for (const auto& resolvedPosition
: tracksSpan
) {
541 GridTrack
& track
= tracks
[resolvedPosition
.toInt()];
542 allocatedSpace
+= track
.baseSize();
544 GridTrackSize trackSize
= gridTrackSize(direction
, resolvedPosition
.toInt());
545 if (!trackSize
.maxTrackBreadth().isFlex())
548 tracksForNormalization
.append(GridTrackForNormalization(track
, trackSize
.maxTrackBreadth().flex()));
551 // The function is not called if we don't have <flex> grid tracks
552 ASSERT(!tracksForNormalization
.isEmpty());
554 std::sort(tracksForNormalization
.begin(), tracksForNormalization
.end(), sortByGridNormalizedFlexValue
);
556 // These values work together: as we walk over our grid tracks, we increase fractionValueBasedOnGridItemsRatio
557 // to match a grid track's usedBreadth to <flex> ratio until the total fractions sized grid tracks wouldn't
558 // fit into availableLogicalSpaceIgnoringFractionTracks.
559 double accumulatedFractions
= 0;
560 LayoutUnit fractionValueBasedOnGridItemsRatio
= 0;
561 LayoutUnit availableLogicalSpaceIgnoringFractionTracks
= spaceToFill
- allocatedSpace
;
563 for (const auto& track
: tracksForNormalization
) {
564 if (track
.m_normalizedFlexValue
> fractionValueBasedOnGridItemsRatio
) {
565 // If the normalized flex value (we ordered |tracksForNormalization| by increasing normalized flex value)
566 // will make us overflow our container, then stop. We have the previous step's ratio is the best fit.
567 if (track
.m_normalizedFlexValue
* accumulatedFractions
> availableLogicalSpaceIgnoringFractionTracks
)
570 fractionValueBasedOnGridItemsRatio
= track
.m_normalizedFlexValue
;
573 accumulatedFractions
+= track
.m_flex
;
574 // This item was processed so we re-add its used breadth to the available space to accurately count the remaining space.
575 availableLogicalSpaceIgnoringFractionTracks
+= track
.m_track
->baseSize();
578 // Let flex factor sum be the sum of the flex factors of the flexible tracks. If this value
579 // is less than 1, set it to 1 instead.
580 if (accumulatedFractions
< 1)
581 return availableLogicalSpaceIgnoringFractionTracks
;
583 return availableLogicalSpaceIgnoringFractionTracks
/ accumulatedFractions
;
586 bool LayoutGrid::hasDefiniteLogicalSize(GridTrackSizingDirection direction
) const
588 return (direction
== ForRows
) ? hasDefiniteLogicalHeight() : hasDefiniteLogicalWidth();
591 GridTrackSize
LayoutGrid::gridTrackSize(GridTrackSizingDirection direction
, size_t i
) const
593 bool isForColumns
= direction
== ForColumns
;
594 const Vector
<GridTrackSize
>& trackStyles
= isForColumns
? style()->gridTemplateColumns() : style()->gridTemplateRows();
595 const GridTrackSize
& trackSize
= (i
>= trackStyles
.size()) ? (isForColumns
? style()->gridAutoColumns() : style()->gridAutoRows()) : trackStyles
[i
];
597 GridLength minTrackBreadth
= trackSize
.minTrackBreadth();
598 GridLength maxTrackBreadth
= trackSize
.maxTrackBreadth();
600 // If the logical width/height of the grid container is indefinite, percentage values are treated as <auto> (or in
601 // the case of minmax() as min-content for the first position and max-content for the second).
602 if (minTrackBreadth
.hasPercentage() || maxTrackBreadth
.hasPercentage()) {
603 if (!hasDefiniteLogicalSize(direction
)) {
604 if (minTrackBreadth
.hasPercentage())
605 minTrackBreadth
= Length(MinContent
);
606 if (maxTrackBreadth
.hasPercentage())
607 maxTrackBreadth
= Length(MaxContent
);
611 return GridTrackSize(minTrackBreadth
, maxTrackBreadth
);
614 LayoutUnit
LayoutGrid::logicalHeightForChild(LayoutBox
& child
, Vector
<GridTrack
>& columnTracks
)
616 SubtreeLayoutScope
layoutScope(child
);
617 LayoutUnit oldOverrideContainingBlockContentLogicalWidth
= child
.hasOverrideContainingBlockLogicalWidth() ? child
.overrideContainingBlockContentLogicalWidth() : LayoutUnit();
618 LayoutUnit overrideContainingBlockContentLogicalWidth
= gridAreaBreadthForChild(child
, ForColumns
, columnTracks
);
619 if (child
.hasRelativeLogicalHeight() || oldOverrideContainingBlockContentLogicalWidth
!= overrideContainingBlockContentLogicalWidth
) {
620 layoutScope
.setNeedsLayout(&child
, LayoutInvalidationReason::GridChanged
);
623 bool hasOverrideHeight
= child
.hasOverrideLogicalContentHeight();
624 // We need to clear the stretched height to properly compute logical height during layout.
625 if (hasOverrideHeight
&& child
.needsLayout())
626 child
.clearOverrideLogicalContentHeight();
628 child
.setOverrideContainingBlockContentLogicalWidth(overrideContainingBlockContentLogicalWidth
);
629 // If |child| has a relative logical height, we shouldn't let it override its intrinsic height, which is
630 // what we are interested in here. Thus we need to set the override logical height to -1 (no possible resolution).
631 if (child
.hasRelativeLogicalHeight())
632 child
.setOverrideContainingBlockContentLogicalHeight(-1);
633 child
.layoutIfNeeded();
634 // If the child was stretched we should use its intrinsic height.
635 return (hasOverrideHeight
? childIntrinsicHeight(child
) : child
.logicalHeight()) + child
.marginLogicalHeight();
638 LayoutUnit
LayoutGrid::minSizeForChild(LayoutBox
& child
, GridTrackSizingDirection direction
, Vector
<GridTrack
>& columnTracks
)
640 bool hasOrthogonalWritingMode
= child
.isHorizontalWritingMode() != isHorizontalWritingMode();
641 // TODO(svillar): Properly support orthogonal writing mode.
642 if (hasOrthogonalWritingMode
)
645 const Length
& childMinSize
= direction
== ForColumns
? child
.style()->logicalMinWidth() : child
.style()->logicalMinHeight();
646 if (childMinSize
.isAuto()) {
647 // TODO(svillar): Implement intrinsic aspect ratio support (transferred size in specs).
648 return minContentForChild(child
, direction
, columnTracks
);
651 if (direction
== ForColumns
)
652 return child
.computeLogicalWidthUsing(MinSize
, childMinSize
, contentLogicalWidth(), this);
654 return child
.computeContentLogicalHeight(MinSize
, childMinSize
, child
.logicalHeight()) + child
.scrollbarLogicalHeight();
657 LayoutUnit
LayoutGrid::minContentForChild(LayoutBox
& child
, GridTrackSizingDirection direction
, Vector
<GridTrack
>& columnTracks
)
659 bool hasOrthogonalWritingMode
= child
.isHorizontalWritingMode() != isHorizontalWritingMode();
660 // FIXME: Properly support orthogonal writing mode.
661 if (hasOrthogonalWritingMode
)
664 if (direction
== ForColumns
) {
665 // If |child| has a relative logical width, we shouldn't let it override its intrinsic width, which is
666 // what we are interested in here. Thus we need to set the override logical width to -1 (no possible resolution).
667 if (child
.hasRelativeLogicalWidth())
668 child
.setOverrideContainingBlockContentLogicalWidth(-1);
670 // FIXME: It's unclear if we should return the intrinsic width or the preferred width.
671 // See http://lists.w3.org/Archives/Public/www-style/2013Jan/0245.html
672 return child
.minPreferredLogicalWidth() + marginIntrinsicLogicalWidthForChild(child
);
675 return logicalHeightForChild(child
, columnTracks
);
678 LayoutUnit
LayoutGrid::maxContentForChild(LayoutBox
& child
, GridTrackSizingDirection direction
, Vector
<GridTrack
>& columnTracks
)
680 bool hasOrthogonalWritingMode
= child
.isHorizontalWritingMode() != isHorizontalWritingMode();
681 // FIXME: Properly support orthogonal writing mode.
682 if (hasOrthogonalWritingMode
)
685 if (direction
== ForColumns
) {
686 // If |child| has a relative logical width, we shouldn't let it override its intrinsic width, which is
687 // what we are interested in here. Thus we need to set the override logical width to -1 (no possible resolution).
688 if (child
.hasRelativeLogicalWidth())
689 child
.setOverrideContainingBlockContentLogicalWidth(-1);
691 // FIXME: It's unclear if we should return the intrinsic width or the preferred width.
692 // See http://lists.w3.org/Archives/Public/www-style/2013Jan/0245.html
693 return child
.maxPreferredLogicalWidth() + marginIntrinsicLogicalWidthForChild(child
);
696 return logicalHeightForChild(child
, columnTracks
);
699 // We're basically using a class instead of a std::pair for two reasons. First of all, accessing gridItem() or
700 // coordinate() is much more self-explanatory that using .first or .second members in the pair. Secondly the class
701 // allows us to precompute the value of the span, something which is quite convenient for the sorting. Having a
702 // std::pair<LayoutBox*, size_t> does not work either because we still need the GridCoordinate so we'd have to add an
703 // extra hash lookup for each item at the beginning of LayoutGrid::resolveContentBasedTrackSizingFunctionsForItems().
704 class GridItemWithSpan
{
706 GridItemWithSpan(LayoutBox
& gridItem
, const GridCoordinate
& coordinate
, GridTrackSizingDirection direction
)
707 : m_gridItem(&gridItem
)
708 , m_coordinate(coordinate
)
710 const GridSpan
& span
= (direction
== ForRows
) ? coordinate
.rows
: coordinate
.columns
;
711 m_span
= span
.resolvedFinalPosition
.toInt() - span
.resolvedInitialPosition
.toInt() + 1;
714 LayoutBox
& gridItem() const { return *m_gridItem
; }
715 GridCoordinate
coordinate() const { return m_coordinate
; }
717 size_t span() const { return m_span
; }
720 bool operator<(const GridItemWithSpan other
) const { return m_span
< other
.m_span
; }
723 LayoutBox
* m_gridItem
;
724 GridCoordinate m_coordinate
;
728 bool LayoutGrid::spanningItemCrossesFlexibleSizedTracks(const GridCoordinate
& coordinate
, GridTrackSizingDirection direction
) const
730 const GridResolvedPosition initialTrackPosition
= (direction
== ForColumns
) ? coordinate
.columns
.resolvedInitialPosition
: coordinate
.rows
.resolvedInitialPosition
;
731 const GridResolvedPosition finalTrackPosition
= (direction
== ForColumns
) ? coordinate
.columns
.resolvedFinalPosition
: coordinate
.rows
.resolvedFinalPosition
;
733 for (GridResolvedPosition trackPosition
= initialTrackPosition
; trackPosition
<= finalTrackPosition
; ++trackPosition
) {
734 const GridTrackSize
& trackSize
= gridTrackSize(direction
, trackPosition
.toInt());
735 if (trackSize
.minTrackBreadth().isFlex() || trackSize
.maxTrackBreadth().isFlex())
742 static inline size_t integerSpanForDirection(const GridCoordinate
& coordinate
, GridTrackSizingDirection direction
)
744 return (direction
== ForRows
) ? coordinate
.rows
.integerSpan() : coordinate
.columns
.integerSpan();
747 void LayoutGrid::resolveContentBasedTrackSizingFunctions(GridTrackSizingDirection direction
, GridSizingData
& sizingData
)
749 sizingData
.itemsSortedByIncreasingSpan
.shrink(0);
750 HashSet
<LayoutBox
*> itemsSet
;
751 for (const auto& trackIndex
: sizingData
.contentSizedTracksIndex
) {
752 GridIterator
iterator(m_grid
, direction
, trackIndex
);
753 GridTrack
& track
= (direction
== ForColumns
) ? sizingData
.columnTracks
[trackIndex
] : sizingData
.rowTracks
[trackIndex
];
754 while (LayoutBox
* gridItem
= iterator
.nextGridItem()) {
755 if (itemsSet
.add(gridItem
).isNewEntry
) {
756 const GridCoordinate
& coordinate
= cachedGridCoordinate(*gridItem
);
757 if (integerSpanForDirection(coordinate
, direction
) == 1) {
758 resolveContentBasedTrackSizingFunctionsForNonSpanningItems(direction
, coordinate
, *gridItem
, track
, sizingData
.columnTracks
);
759 } else if (!spanningItemCrossesFlexibleSizedTracks(coordinate
, direction
)) {
760 sizingData
.itemsSortedByIncreasingSpan
.append(GridItemWithSpan(*gridItem
, coordinate
, direction
));
765 std::sort(sizingData
.itemsSortedByIncreasingSpan
.begin(), sizingData
.itemsSortedByIncreasingSpan
.end());
767 auto it
= sizingData
.itemsSortedByIncreasingSpan
.begin();
768 auto end
= sizingData
.itemsSortedByIncreasingSpan
.end();
770 GridItemsSpanGroupRange spanGroupRange
= { it
, std::upper_bound(it
, end
, *it
) };
771 resolveContentBasedTrackSizingFunctionsForItems
<ResolveIntrinsicMinimums
>(direction
, sizingData
, spanGroupRange
);
772 resolveContentBasedTrackSizingFunctionsForItems
<ResolveContentBasedMinimums
>(direction
, sizingData
, spanGroupRange
);
773 resolveContentBasedTrackSizingFunctionsForItems
<ResolveMaxContentMinimums
>(direction
, sizingData
, spanGroupRange
);
774 resolveContentBasedTrackSizingFunctionsForItems
<ResolveIntrinsicMaximums
>(direction
, sizingData
, spanGroupRange
);
775 resolveContentBasedTrackSizingFunctionsForItems
<ResolveMaxContentMaximums
>(direction
, sizingData
, spanGroupRange
);
776 it
= spanGroupRange
.rangeEnd
;
779 for (const auto& trackIndex
: sizingData
.contentSizedTracksIndex
) {
780 GridTrack
& track
= (direction
== ForColumns
) ? sizingData
.columnTracks
[trackIndex
] : sizingData
.rowTracks
[trackIndex
];
781 if (track
.growthLimitIsInfinite())
782 track
.setGrowthLimit(track
.baseSize());
786 void LayoutGrid::resolveContentBasedTrackSizingFunctionsForNonSpanningItems(GridTrackSizingDirection direction
, const GridCoordinate
& coordinate
, LayoutBox
& gridItem
, GridTrack
& track
, Vector
<GridTrack
>& columnTracks
)
788 const GridResolvedPosition trackPosition
= (direction
== ForColumns
) ? coordinate
.columns
.resolvedInitialPosition
: coordinate
.rows
.resolvedInitialPosition
;
789 GridTrackSize trackSize
= gridTrackSize(direction
, trackPosition
.toInt());
791 if (trackSize
.hasMinContentMinTrackBreadth())
792 track
.setBaseSize(std::max(track
.baseSize(), minContentForChild(gridItem
, direction
, columnTracks
)));
793 else if (trackSize
.hasMaxContentMinTrackBreadth())
794 track
.setBaseSize(std::max(track
.baseSize(), maxContentForChild(gridItem
, direction
, columnTracks
)));
795 else if (trackSize
.hasAutoMinTrackBreadth())
796 track
.setBaseSize(std::max(track
.baseSize(), minSizeForChild(gridItem
, direction
, columnTracks
)));
798 if (trackSize
.hasMinContentMaxTrackBreadth())
799 track
.setGrowthLimit(std::max(track
.growthLimit(), minContentForChild(gridItem
, direction
, columnTracks
)));
800 else if (trackSize
.hasMaxContentOrAutoMaxTrackBreadth())
801 track
.setGrowthLimit(std::max(track
.growthLimit(), maxContentForChild(gridItem
, direction
, columnTracks
)));
804 static const LayoutUnit
& trackSizeForTrackSizeComputationPhase(TrackSizeComputationPhase phase
, const GridTrack
& track
, TrackSizeRestriction restriction
)
807 case ResolveIntrinsicMinimums
:
808 case ResolveContentBasedMinimums
:
809 case ResolveMaxContentMinimums
:
811 return track
.baseSize();
812 case ResolveIntrinsicMaximums
:
813 case ResolveMaxContentMaximums
:
814 const LayoutUnit
& growthLimit
= track
.growthLimit();
815 if (restriction
== AllowInfinity
)
817 return growthLimit
== infinity
? track
.baseSize() : growthLimit
;
820 ASSERT_NOT_REACHED();
821 return track
.baseSize();
824 static bool shouldProcessTrackForTrackSizeComputationPhase(TrackSizeComputationPhase phase
, const GridTrackSize
& trackSize
)
827 case ResolveIntrinsicMinimums
:
828 return trackSize
.hasIntrinsicMinTrackBreadth();
829 case ResolveContentBasedMinimums
:
830 return trackSize
.hasMinOrMaxContentMinTrackBreadth();
831 case ResolveMaxContentMinimums
:
832 return trackSize
.hasMaxContentMinTrackBreadth();
833 case ResolveIntrinsicMaximums
:
834 return trackSize
.hasMinOrMaxContentMaxTrackBreadth();
835 case ResolveMaxContentMaximums
:
836 return trackSize
.hasMaxContentOrAutoMaxTrackBreadth();
838 ASSERT_NOT_REACHED();
842 ASSERT_NOT_REACHED();
846 static bool trackShouldGrowBeyondGrowthLimitsForTrackSizeComputationPhase(TrackSizeComputationPhase phase
, const GridTrackSize
& trackSize
)
849 case ResolveIntrinsicMinimums
:
850 case ResolveContentBasedMinimums
:
851 return trackSize
.hasAutoOrMinContentMinTrackBreadthAndIntrinsicMaxTrackBreadth();
852 case ResolveMaxContentMinimums
:
853 return trackSize
.hasMaxContentMinTrackBreadthAndMaxContentMaxTrackBreadth();
854 case ResolveIntrinsicMaximums
:
855 case ResolveMaxContentMaximums
:
858 ASSERT_NOT_REACHED();
862 ASSERT_NOT_REACHED();
866 static void markAsInfinitelyGrowableForTrackSizeComputationPhase(TrackSizeComputationPhase phase
, GridTrack
& track
)
869 case ResolveIntrinsicMinimums
:
870 case ResolveContentBasedMinimums
:
871 case ResolveMaxContentMinimums
:
873 case ResolveIntrinsicMaximums
:
874 if (trackSizeForTrackSizeComputationPhase(phase
, track
, AllowInfinity
) == infinity
&& track
.plannedSize() != infinity
)
875 track
.setInfinitelyGrowable(true);
877 case ResolveMaxContentMaximums
:
878 if (track
.infinitelyGrowable())
879 track
.setInfinitelyGrowable(false);
882 ASSERT_NOT_REACHED();
886 ASSERT_NOT_REACHED();
889 static void updateTrackSizeForTrackSizeComputationPhase(TrackSizeComputationPhase phase
, GridTrack
& track
)
892 case ResolveIntrinsicMinimums
:
893 case ResolveContentBasedMinimums
:
894 case ResolveMaxContentMinimums
:
895 track
.setBaseSize(track
.plannedSize());
897 case ResolveIntrinsicMaximums
:
898 case ResolveMaxContentMaximums
:
899 track
.setGrowthLimit(track
.plannedSize());
902 ASSERT_NOT_REACHED();
906 ASSERT_NOT_REACHED();
909 LayoutUnit
LayoutGrid::currentItemSizeForTrackSizeComputationPhase(TrackSizeComputationPhase phase
, LayoutBox
& gridItem
, GridTrackSizingDirection direction
, Vector
<GridTrack
>& columnTracks
)
912 case ResolveIntrinsicMinimums
:
913 return minSizeForChild(gridItem
, direction
, columnTracks
);
914 case ResolveContentBasedMinimums
:
915 case ResolveIntrinsicMaximums
:
916 return minContentForChild(gridItem
, direction
, columnTracks
);
917 case ResolveMaxContentMinimums
:
918 case ResolveMaxContentMaximums
:
919 return maxContentForChild(gridItem
, direction
, columnTracks
);
921 ASSERT_NOT_REACHED();
925 ASSERT_NOT_REACHED();
929 template <TrackSizeComputationPhase phase
>
930 void LayoutGrid::resolveContentBasedTrackSizingFunctionsForItems(GridTrackSizingDirection direction
, GridSizingData
& sizingData
, const GridItemsSpanGroupRange
& gridItemsWithSpan
)
932 Vector
<GridTrack
>& tracks
= (direction
== ForColumns
) ? sizingData
.columnTracks
: sizingData
.rowTracks
;
933 for (const auto& trackIndex
: sizingData
.contentSizedTracksIndex
) {
934 GridTrack
& track
= tracks
[trackIndex
];
935 track
.setPlannedSize(trackSizeForTrackSizeComputationPhase(phase
, track
, AllowInfinity
));
938 for (auto it
= gridItemsWithSpan
.rangeStart
; it
!= gridItemsWithSpan
.rangeEnd
; ++it
) {
939 GridItemWithSpan
& gridItemWithSpan
= *it
;
940 ASSERT(gridItemWithSpan
.span() > 1);
941 const GridCoordinate coordinate
= gridItemWithSpan
.coordinate();
942 const GridSpan
& itemSpan
= (direction
== ForColumns
) ? coordinate
.columns
: coordinate
.rows
;
944 sizingData
.growBeyondGrowthLimitsTracks
.shrink(0);
945 sizingData
.filteredTracks
.shrink(0);
946 LayoutUnit spanningTracksSize
;
947 for (const auto& trackPosition
: itemSpan
) {
948 GridTrackSize trackSize
= gridTrackSize(direction
, trackPosition
.toInt());
949 GridTrack
& track
= (direction
== ForColumns
) ? sizingData
.columnTracks
[trackPosition
.toInt()] : sizingData
.rowTracks
[trackPosition
.toInt()];
950 spanningTracksSize
+= trackSizeForTrackSizeComputationPhase(phase
, track
, ForbidInfinity
);
951 if (!shouldProcessTrackForTrackSizeComputationPhase(phase
, trackSize
))
954 sizingData
.filteredTracks
.append(&track
);
956 if (trackShouldGrowBeyondGrowthLimitsForTrackSizeComputationPhase(phase
, trackSize
))
957 sizingData
.growBeyondGrowthLimitsTracks
.append(&track
);
960 if (sizingData
.filteredTracks
.isEmpty())
963 LayoutUnit extraSpace
= currentItemSizeForTrackSizeComputationPhase(phase
, gridItemWithSpan
.gridItem(), direction
, sizingData
.columnTracks
) - spanningTracksSize
;
964 extraSpace
= std::max
<LayoutUnit
>(extraSpace
, 0);
965 auto& tracksToGrowBeyondGrowthLimits
= sizingData
.growBeyondGrowthLimitsTracks
.isEmpty() ? sizingData
.filteredTracks
: sizingData
.growBeyondGrowthLimitsTracks
;
966 distributeSpaceToTracks
<phase
>(sizingData
.filteredTracks
, &tracksToGrowBeyondGrowthLimits
, sizingData
, extraSpace
);
969 for (const auto& trackIndex
: sizingData
.contentSizedTracksIndex
) {
970 GridTrack
& track
= tracks
[trackIndex
];
971 markAsInfinitelyGrowableForTrackSizeComputationPhase(phase
, track
);
972 updateTrackSizeForTrackSizeComputationPhase(phase
, track
);
976 static bool sortByGridTrackGrowthPotential(const GridTrack
* track1
, const GridTrack
* track2
)
978 // This check ensures that we respect the irreflexivity property of the strict weak ordering required by std::sort
979 // (forall x: NOT x < x).
980 if (track1
->infiniteGrowthPotential() && track2
->infiniteGrowthPotential())
983 if (track1
->infiniteGrowthPotential() || track2
->infiniteGrowthPotential())
984 return track2
->infiniteGrowthPotential();
986 return (track1
->growthLimit() - track1
->baseSize()) < (track2
->growthLimit() - track2
->baseSize());
989 template <TrackSizeComputationPhase phase
>
990 void LayoutGrid::distributeSpaceToTracks(Vector
<GridTrack
*>& tracks
, const Vector
<GridTrack
*>* growBeyondGrowthLimitsTracks
, GridSizingData
& sizingData
, LayoutUnit
& availableLogicalSpace
)
992 ASSERT(availableLogicalSpace
>= 0);
994 for (auto* track
: tracks
)
995 track
->setSizeDuringDistribution(trackSizeForTrackSizeComputationPhase(phase
, *track
, ForbidInfinity
));
997 if (availableLogicalSpace
> 0) {
998 std::sort(tracks
.begin(), tracks
.end(), sortByGridTrackGrowthPotential
);
1000 size_t tracksSize
= tracks
.size();
1001 for (size_t i
= 0; i
< tracksSize
; ++i
) {
1002 GridTrack
& track
= *tracks
[i
];
1003 LayoutUnit availableLogicalSpaceShare
= availableLogicalSpace
/ (tracksSize
- i
);
1004 const LayoutUnit
& trackBreadth
= trackSizeForTrackSizeComputationPhase(phase
, track
, ForbidInfinity
);
1005 LayoutUnit growthShare
= track
.infiniteGrowthPotential() ? availableLogicalSpaceShare
: std::min(availableLogicalSpaceShare
, track
.growthLimit() - trackBreadth
);
1006 ASSERT_WITH_MESSAGE(growthShare
>= 0, "We must never shrink any grid track or else we can't guarantee we abide by our min-sizing function.");
1007 track
.growSizeDuringDistribution(growthShare
);
1008 availableLogicalSpace
-= growthShare
;
1012 if (availableLogicalSpace
> 0 && growBeyondGrowthLimitsTracks
) {
1013 size_t tracksGrowingAboveMaxBreadthSize
= growBeyondGrowthLimitsTracks
->size();
1014 for (size_t i
= 0; i
< tracksGrowingAboveMaxBreadthSize
; ++i
) {
1015 GridTrack
* track
= growBeyondGrowthLimitsTracks
->at(i
);
1016 LayoutUnit growthShare
= availableLogicalSpace
/ (tracksGrowingAboveMaxBreadthSize
- i
);
1017 track
->growSizeDuringDistribution(growthShare
);
1018 availableLogicalSpace
-= growthShare
;
1022 for (auto* track
: tracks
)
1023 track
->setPlannedSize(track
->plannedSize() == infinity
? track
->sizeDuringDistribution() : std::max(track
->plannedSize(), track
->sizeDuringDistribution()));
1027 bool LayoutGrid::tracksAreWiderThanMinTrackBreadth(GridTrackSizingDirection direction
, const Vector
<GridTrack
>& tracks
)
1029 for (size_t i
= 0; i
< tracks
.size(); ++i
) {
1030 GridTrackSize trackSize
= gridTrackSize(direction
, i
);
1031 const GridLength
& minTrackBreadth
= trackSize
.minTrackBreadth();
1032 if (computeUsedBreadthOfMinLength(direction
, minTrackBreadth
) > tracks
[i
].baseSize())
1039 void LayoutGrid::ensureGridSize(size_t maximumRowIndex
, size_t maximumColumnIndex
)
1041 const size_t oldRowSize
= gridRowCount();
1042 if (maximumRowIndex
>= oldRowSize
) {
1043 m_grid
.grow(maximumRowIndex
+ 1);
1044 for (size_t row
= oldRowSize
; row
< gridRowCount(); ++row
)
1045 m_grid
[row
].grow(gridColumnCount());
1048 if (maximumColumnIndex
>= gridColumnCount()) {
1049 for (size_t row
= 0; row
< gridRowCount(); ++row
)
1050 m_grid
[row
].grow(maximumColumnIndex
+ 1);
1054 void LayoutGrid::insertItemIntoGrid(LayoutBox
& child
, const GridCoordinate
& coordinate
)
1056 ensureGridSize(coordinate
.rows
.resolvedFinalPosition
.toInt(), coordinate
.columns
.resolvedFinalPosition
.toInt());
1058 for (GridSpan::iterator row
= coordinate
.rows
.begin(); row
!= coordinate
.rows
.end(); ++row
) {
1059 for (GridSpan::iterator column
= coordinate
.columns
.begin(); column
!= coordinate
.columns
.end(); ++column
)
1060 m_grid
[row
.toInt()][column
.toInt()].append(&child
);
1063 RELEASE_ASSERT(!m_gridItemCoordinate
.contains(&child
));
1064 m_gridItemCoordinate
.set(&child
, coordinate
);
1067 void LayoutGrid::placeItemsOnGrid()
1072 ASSERT(m_gridItemCoordinate
.isEmpty());
1074 populateExplicitGridAndOrderIterator();
1076 // We clear the dirty bit here as the grid sizes have been updated.
1077 m_gridIsDirty
= false;
1079 Vector
<LayoutBox
*> autoMajorAxisAutoGridItems
;
1080 Vector
<LayoutBox
*> specifiedMajorAxisAutoGridItems
;
1081 for (LayoutBox
* child
= m_orderIterator
.first(); child
; child
= m_orderIterator
.next()) {
1082 if (child
->isOutOfFlowPositioned())
1085 OwnPtr
<GridSpan
> rowPositions
= GridResolvedPosition::resolveGridPositionsFromStyle(*style(), *child
, ForRows
);
1086 OwnPtr
<GridSpan
> columnPositions
= GridResolvedPosition::resolveGridPositionsFromStyle(*style(), *child
, ForColumns
);
1087 if (!rowPositions
|| !columnPositions
) {
1088 GridSpan
* majorAxisPositions
= (autoPlacementMajorAxisDirection() == ForColumns
) ? columnPositions
.get() : rowPositions
.get();
1089 if (!majorAxisPositions
)
1090 autoMajorAxisAutoGridItems
.append(child
);
1092 specifiedMajorAxisAutoGridItems
.append(child
);
1095 insertItemIntoGrid(*child
, GridCoordinate(*rowPositions
, *columnPositions
));
1098 ASSERT(gridRowCount() >= GridResolvedPosition::explicitGridRowCount(*style()));
1099 ASSERT(gridColumnCount() >= GridResolvedPosition::explicitGridColumnCount(*style()));
1101 placeSpecifiedMajorAxisItemsOnGrid(specifiedMajorAxisAutoGridItems
);
1102 placeAutoMajorAxisItemsOnGrid(autoMajorAxisAutoGridItems
);
1104 m_grid
.shrinkToFit();
1107 void LayoutGrid::populateExplicitGridAndOrderIterator()
1109 OrderIteratorPopulator
populator(m_orderIterator
);
1111 size_t maximumRowIndex
= std::max
<size_t>(1, GridResolvedPosition::explicitGridRowCount(*style()));
1112 size_t maximumColumnIndex
= std::max
<size_t>(1, GridResolvedPosition::explicitGridColumnCount(*style()));
1114 ASSERT(m_gridItemsIndexesMap
.isEmpty());
1115 size_t childIndex
= 0;
1116 for (LayoutBox
* child
= firstChildBox(); child
; child
= child
->nextInFlowSiblingBox()) {
1117 populator
.collectChild(child
);
1118 m_gridItemsIndexesMap
.set(child
, childIndex
++);
1120 // This function bypasses the cache (cachedGridCoordinate()) as it is used to build it.
1121 OwnPtr
<GridSpan
> rowPositions
= GridResolvedPosition::resolveGridPositionsFromStyle(*style(), *child
, ForRows
);
1122 OwnPtr
<GridSpan
> columnPositions
= GridResolvedPosition::resolveGridPositionsFromStyle(*style(), *child
, ForColumns
);
1124 // |positions| is 0 if we need to run the auto-placement algorithm.
1126 maximumRowIndex
= std::max
<size_t>(maximumRowIndex
, rowPositions
->resolvedFinalPosition
.next().toInt());
1128 // Grow the grid for items with a definite row span, getting the largest such span.
1129 GridSpan positions
= GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), *child
, ForRows
, GridResolvedPosition(0));
1130 maximumRowIndex
= std::max
<size_t>(maximumRowIndex
, positions
.resolvedFinalPosition
.next().toInt());
1133 if (columnPositions
) {
1134 maximumColumnIndex
= std::max
<size_t>(maximumColumnIndex
, columnPositions
->resolvedFinalPosition
.next().toInt());
1136 // Grow the grid for items with a definite column span, getting the largest such span.
1137 GridSpan positions
= GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), *child
, ForColumns
, GridResolvedPosition(0));
1138 maximumColumnIndex
= std::max
<size_t>(maximumColumnIndex
, positions
.resolvedFinalPosition
.next().toInt());
1142 m_grid
.grow(maximumRowIndex
);
1143 for (auto& column
: m_grid
)
1144 column
.grow(maximumColumnIndex
);
1147 PassOwnPtr
<GridCoordinate
> LayoutGrid::createEmptyGridAreaAtSpecifiedPositionsOutsideGrid(const LayoutBox
& gridItem
, GridTrackSizingDirection specifiedDirection
, const GridSpan
& specifiedPositions
) const
1149 GridTrackSizingDirection crossDirection
= specifiedDirection
== ForColumns
? ForRows
: ForColumns
;
1150 const size_t endOfCrossDirection
= crossDirection
== ForColumns
? gridColumnCount() : gridRowCount();
1151 GridSpan crossDirectionPositions
= GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), gridItem
, crossDirection
, GridResolvedPosition(endOfCrossDirection
));
1152 return adoptPtr(new GridCoordinate(specifiedDirection
== ForColumns
? crossDirectionPositions
: specifiedPositions
, specifiedDirection
== ForColumns
? specifiedPositions
: crossDirectionPositions
));
1155 void LayoutGrid::placeSpecifiedMajorAxisItemsOnGrid(const Vector
<LayoutBox
*>& autoGridItems
)
1157 bool isForColumns
= autoPlacementMajorAxisDirection() == ForColumns
;
1158 bool isGridAutoFlowDense
= style()->isGridAutoFlowAlgorithmDense();
1160 // Mapping between the major axis tracks (rows or columns) and the last auto-placed item's position inserted on
1161 // that track. This is needed to implement "sparse" packing for items locked to a given track.
1162 // See http://dev.w3.org/csswg/css-grid/#auto-placement-algo
1163 HashMap
<unsigned, unsigned, DefaultHash
<unsigned>::Hash
, WTF::UnsignedWithZeroKeyHashTraits
<unsigned>> minorAxisCursors
;
1165 for (const auto& autoGridItem
: autoGridItems
) {
1166 OwnPtr
<GridSpan
> majorAxisPositions
= GridResolvedPosition::resolveGridPositionsFromStyle(*style(), *autoGridItem
, autoPlacementMajorAxisDirection());
1167 GridSpan minorAxisPositions
= GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), *autoGridItem
, autoPlacementMinorAxisDirection(), GridResolvedPosition(0));
1168 unsigned majorAxisInitialPosition
= majorAxisPositions
->resolvedInitialPosition
.toInt();
1170 GridIterator
iterator(m_grid
, autoPlacementMajorAxisDirection(), majorAxisPositions
->resolvedInitialPosition
.toInt(), isGridAutoFlowDense
? 0 : minorAxisCursors
.get(majorAxisInitialPosition
));
1171 OwnPtr
<GridCoordinate
> emptyGridArea
= iterator
.nextEmptyGridArea(majorAxisPositions
->integerSpan(), minorAxisPositions
.integerSpan());
1173 emptyGridArea
= createEmptyGridAreaAtSpecifiedPositionsOutsideGrid(*autoGridItem
, autoPlacementMajorAxisDirection(), *majorAxisPositions
);
1174 insertItemIntoGrid(*autoGridItem
, *emptyGridArea
);
1176 if (!isGridAutoFlowDense
)
1177 minorAxisCursors
.set(majorAxisInitialPosition
, isForColumns
? emptyGridArea
->rows
.resolvedInitialPosition
.toInt() : emptyGridArea
->columns
.resolvedInitialPosition
.toInt());
1181 void LayoutGrid::placeAutoMajorAxisItemsOnGrid(const Vector
<LayoutBox
*>& autoGridItems
)
1183 std::pair
<size_t, size_t> autoPlacementCursor
= std::make_pair(0, 0);
1184 bool isGridAutoFlowDense
= style()->isGridAutoFlowAlgorithmDense();
1186 for (const auto& autoGridItem
: autoGridItems
) {
1187 placeAutoMajorAxisItemOnGrid(*autoGridItem
, autoPlacementCursor
);
1189 // If grid-auto-flow is dense, reset auto-placement cursor.
1190 if (isGridAutoFlowDense
) {
1191 autoPlacementCursor
.first
= 0;
1192 autoPlacementCursor
.second
= 0;
1197 void LayoutGrid::placeAutoMajorAxisItemOnGrid(LayoutBox
& gridItem
, std::pair
<size_t, size_t>& autoPlacementCursor
)
1199 OwnPtr
<GridSpan
> minorAxisPositions
= GridResolvedPosition::resolveGridPositionsFromStyle(*style(), gridItem
, autoPlacementMinorAxisDirection());
1200 ASSERT(!GridResolvedPosition::resolveGridPositionsFromStyle(*style(), gridItem
, autoPlacementMajorAxisDirection()));
1201 GridSpan majorAxisPositions
= GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), gridItem
, autoPlacementMajorAxisDirection(), GridResolvedPosition(0));
1203 const size_t endOfMajorAxis
= (autoPlacementMajorAxisDirection() == ForColumns
) ? gridColumnCount() : gridRowCount();
1204 size_t majorAxisAutoPlacementCursor
= autoPlacementMajorAxisDirection() == ForColumns
? autoPlacementCursor
.second
: autoPlacementCursor
.first
;
1205 size_t minorAxisAutoPlacementCursor
= autoPlacementMajorAxisDirection() == ForColumns
? autoPlacementCursor
.first
: autoPlacementCursor
.second
;
1207 OwnPtr
<GridCoordinate
> emptyGridArea
;
1208 if (minorAxisPositions
) {
1209 // Move to the next track in major axis if initial position in minor axis is before auto-placement cursor.
1210 if (minorAxisPositions
->resolvedInitialPosition
.toInt() < minorAxisAutoPlacementCursor
)
1211 majorAxisAutoPlacementCursor
++;
1213 if (majorAxisAutoPlacementCursor
< endOfMajorAxis
) {
1214 GridIterator
iterator(m_grid
, autoPlacementMinorAxisDirection(), minorAxisPositions
->resolvedInitialPosition
.toInt(), majorAxisAutoPlacementCursor
);
1215 emptyGridArea
= iterator
.nextEmptyGridArea(minorAxisPositions
->integerSpan(), majorAxisPositions
.integerSpan());
1219 emptyGridArea
= createEmptyGridAreaAtSpecifiedPositionsOutsideGrid(gridItem
, autoPlacementMinorAxisDirection(), *minorAxisPositions
);
1221 GridSpan minorAxisPositions
= GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(*style(), gridItem
, autoPlacementMinorAxisDirection(), GridResolvedPosition(0));
1223 for (size_t majorAxisIndex
= majorAxisAutoPlacementCursor
; majorAxisIndex
< endOfMajorAxis
; ++majorAxisIndex
) {
1224 GridIterator
iterator(m_grid
, autoPlacementMajorAxisDirection(), majorAxisIndex
, minorAxisAutoPlacementCursor
);
1225 emptyGridArea
= iterator
.nextEmptyGridArea(majorAxisPositions
.integerSpan(), minorAxisPositions
.integerSpan());
1227 if (emptyGridArea
) {
1228 // Check that it fits in the minor axis direction, as we shouldn't grow in that direction here (it was already managed in populateExplicitGridAndOrderIterator()).
1229 GridResolvedPosition minorAxisFinalPositionIndex
= autoPlacementMinorAxisDirection() == ForColumns
? emptyGridArea
->columns
.resolvedFinalPosition
: emptyGridArea
->rows
.resolvedFinalPosition
;
1230 const size_t endOfMinorAxis
= autoPlacementMinorAxisDirection() == ForColumns
? gridColumnCount() : gridRowCount();
1231 if (minorAxisFinalPositionIndex
.toInt() < endOfMinorAxis
)
1234 // Discard empty grid area as it does not fit in the minor axis direction.
1235 // We don't need to create a new empty grid area yet as we might find a valid one in the next iteration.
1236 emptyGridArea
= nullptr;
1239 // As we're moving to the next track in the major axis we should reset the auto-placement cursor in the minor axis.
1240 minorAxisAutoPlacementCursor
= 0;
1244 emptyGridArea
= createEmptyGridAreaAtSpecifiedPositionsOutsideGrid(gridItem
, autoPlacementMinorAxisDirection(), minorAxisPositions
);
1247 insertItemIntoGrid(gridItem
, *emptyGridArea
);
1248 // Move auto-placement cursor to the new position.
1249 autoPlacementCursor
.first
= emptyGridArea
->rows
.resolvedInitialPosition
.toInt();
1250 autoPlacementCursor
.second
= emptyGridArea
->columns
.resolvedInitialPosition
.toInt();
1253 GridTrackSizingDirection
LayoutGrid::autoPlacementMajorAxisDirection() const
1255 return style()->isGridAutoFlowDirectionColumn() ? ForColumns
: ForRows
;
1258 GridTrackSizingDirection
LayoutGrid::autoPlacementMinorAxisDirection() const
1260 return style()->isGridAutoFlowDirectionColumn() ? ForRows
: ForColumns
;
1263 void LayoutGrid::dirtyGrid()
1268 // Even if this could be redundant, it could be seen as a defensive strategy against
1269 // style changes events happening during the layout phase or even while the painting process
1270 // is still ongoing.
1271 // Forcing a new layout for the Grid layout would cancel any ongoing painting and ensure
1272 // the grid and its children are correctly laid out according to the new style rules.
1273 setNeedsLayout(LayoutInvalidationReason::GridChanged
);
1276 m_gridItemCoordinate
.clear();
1277 m_gridItemsOverflowingGridArea
.resize(0);
1278 m_gridItemsIndexesMap
.clear();
1279 m_gridIsDirty
= true;
1282 void LayoutGrid::applyStretchAlignmentToTracksIfNeeded(GridTrackSizingDirection direction
, GridSizingData
& sizingData
, LayoutUnit availableSpace
)
1284 if (availableSpace
<= 0
1285 || (direction
== ForColumns
&& styleRef().justifyContentDistribution() != ContentDistributionStretch
)
1286 || (direction
== ForRows
&& styleRef().alignContentDistribution() != ContentDistributionStretch
))
1289 // Spec defines auto-sized tracks as the ones with an 'auto' max-sizing function.
1290 Vector
<GridTrack
>& tracks
= (direction
== ForColumns
) ? sizingData
.columnTracks
: sizingData
.rowTracks
;
1291 Vector
<unsigned> autoSizedTracksIndex
;
1292 for (unsigned i
= 0; i
< tracks
.size(); ++i
) {
1293 const GridTrackSize
& trackSize
= gridTrackSize(direction
, i
);
1294 // If there is some flexible-sized track, they should have exhausted available space during sizing algorithm.
1295 ASSERT(!trackSize
.maxTrackBreadth().isFlex());
1296 if (trackSize
.hasAutoMaxTrackBreadth())
1297 autoSizedTracksIndex
.append(i
);
1300 unsigned numberOfAutoSizedTracks
= autoSizedTracksIndex
.size();
1301 if (numberOfAutoSizedTracks
< 1)
1304 LayoutUnit sizeToIncrease
= availableSpace
/ numberOfAutoSizedTracks
;
1305 for (const auto& trackIndex
: autoSizedTracksIndex
) {
1306 GridTrack
* track
= tracks
.data() + trackIndex
;
1307 LayoutUnit baseSize
= track
->baseSize() + sizeToIncrease
;
1308 track
->setBaseSize(baseSize
);
1312 void LayoutGrid::layoutGridItems()
1316 LayoutUnit availableSpaceForColumns
= availableLogicalWidth();
1317 LayoutUnit availableSpaceForRows
= availableLogicalHeight(IncludeMarginBorderPadding
);
1318 GridSizingData
sizingData(gridColumnCount(), gridRowCount());
1319 computeUsedBreadthOfGridTracks(ForColumns
, sizingData
, availableSpaceForColumns
);
1320 ASSERT(tracksAreWiderThanMinTrackBreadth(ForColumns
, sizingData
.columnTracks
));
1321 computeUsedBreadthOfGridTracks(ForRows
, sizingData
, availableSpaceForRows
);
1322 ASSERT(tracksAreWiderThanMinTrackBreadth(ForRows
, sizingData
.rowTracks
));
1324 applyStretchAlignmentToTracksIfNeeded(ForColumns
, sizingData
, availableSpaceForColumns
);
1325 applyStretchAlignmentToTracksIfNeeded(ForRows
, sizingData
, availableSpaceForRows
);
1327 populateGridPositions(sizingData
, availableSpaceForColumns
, availableSpaceForRows
);
1328 m_gridItemsOverflowingGridArea
.resize(0);
1330 for (LayoutBox
* child
= firstChildBox(); child
; child
= child
->nextSiblingBox()) {
1331 if (child
->isOutOfFlowPositioned()) {
1332 prepareChildForPositionedLayout(*child
);
1336 // Because the grid area cannot be styled, we don't need to adjust
1337 // the grid breadth to account for 'box-sizing'.
1338 LayoutUnit oldOverrideContainingBlockContentLogicalWidth
= child
->hasOverrideContainingBlockLogicalWidth() ? child
->overrideContainingBlockContentLogicalWidth() : LayoutUnit();
1339 LayoutUnit oldOverrideContainingBlockContentLogicalHeight
= child
->hasOverrideContainingBlockLogicalHeight() ? child
->overrideContainingBlockContentLogicalHeight() : LayoutUnit();
1341 LayoutUnit overrideContainingBlockContentLogicalWidth
= gridAreaBreadthForChildIncludingAlignmentOffsets(*child
, ForColumns
, sizingData
);
1342 LayoutUnit overrideContainingBlockContentLogicalHeight
= gridAreaBreadthForChildIncludingAlignmentOffsets(*child
, ForRows
, sizingData
);
1344 SubtreeLayoutScope
layoutScope(*child
);
1345 if (oldOverrideContainingBlockContentLogicalWidth
!= overrideContainingBlockContentLogicalWidth
|| (oldOverrideContainingBlockContentLogicalHeight
!= overrideContainingBlockContentLogicalHeight
&& child
->hasRelativeLogicalHeight()))
1346 layoutScope
.setNeedsLayout(child
, LayoutInvalidationReason::GridChanged
);
1348 child
->setOverrideContainingBlockContentLogicalWidth(overrideContainingBlockContentLogicalWidth
);
1349 child
->setOverrideContainingBlockContentLogicalHeight(overrideContainingBlockContentLogicalHeight
);
1351 // Stretching logic might force a child layout, so we need to run it before the layoutIfNeeded
1352 // call to avoid unnecessary relayouts. This might imply that child margins, needed to correctly
1353 // determine the available space before stretching, are not set yet.
1354 applyStretchAlignmentToChildIfNeeded(*child
);
1356 child
->layoutIfNeeded();
1359 const GridCoordinate
& coordinate
= cachedGridCoordinate(*child
);
1360 ASSERT(coordinate
.columns
.resolvedInitialPosition
.toInt() < sizingData
.columnTracks
.size());
1361 ASSERT(coordinate
.rows
.resolvedInitialPosition
.toInt() < sizingData
.rowTracks
.size());
1363 child
->setLogicalLocation(findChildLogicalPosition(*child
, sizingData
));
1365 // Keep track of children overflowing their grid area as we might need to paint them even if the grid-area is
1367 if (child
->logicalHeight() > overrideContainingBlockContentLogicalHeight
1368 || child
->logicalWidth() > overrideContainingBlockContentLogicalWidth
)
1369 m_gridItemsOverflowingGridArea
.append(child
);
1372 for (const auto& row
: sizingData
.rowTracks
)
1373 setLogicalHeight(logicalHeight() + row
.baseSize());
1375 LayoutUnit height
= logicalHeight() + borderAndPaddingLogicalHeight() + scrollbarLogicalHeight();
1376 if (hasLineIfEmpty())
1377 height
= std::max(height
, minimumLogicalHeightForEmptyLine());
1379 // Min / max logical height is handled by the call to updateLogicalHeight in layoutBlock.
1380 setLogicalHeight(height
);
1383 void LayoutGrid::prepareChildForPositionedLayout(LayoutBox
& child
)
1385 ASSERT(child
.isOutOfFlowPositioned());
1386 child
.containingBlock()->insertPositionedObject(&child
);
1388 DeprecatedPaintLayer
* childLayer
= child
.layer();
1389 childLayer
->setStaticInlinePosition(borderAndPaddingStart());
1390 childLayer
->setStaticBlockPosition(borderAndPaddingBefore());
1393 void LayoutGrid::layoutPositionedObjects(bool relayoutChildren
, PositionedLayoutBehavior info
)
1395 TrackedLayoutBoxListHashSet
* positionedDescendants
= positionedObjects();
1396 if (!positionedDescendants
)
1399 bool containerHasHorizontalWritingMode
= isHorizontalWritingMode();
1400 for (auto* child
: *positionedDescendants
) {
1401 bool hasOrthogonalWritingMode
= child
->isHorizontalWritingMode() != containerHasHorizontalWritingMode
;
1402 if (hasOrthogonalWritingMode
) {
1403 // FIXME: Properly support orthogonal writing mode.
1407 // FIXME: Detect properly if start/end is auto for inexistent named grid lines.
1408 bool columnStartIsAuto
= child
->style()->gridColumnStart().isAuto();
1409 LayoutUnit columnOffset
= LayoutUnit();
1410 LayoutUnit columnBreadth
= LayoutUnit();
1411 offsetAndBreadthForPositionedChild(*child
, ForColumns
, columnStartIsAuto
, child
->style()->gridColumnEnd().isAuto(), columnOffset
, columnBreadth
);
1412 bool rowStartIsAuto
= child
->style()->gridRowStart().isAuto();
1413 LayoutUnit rowOffset
= LayoutUnit();
1414 LayoutUnit rowBreadth
= LayoutUnit();
1415 offsetAndBreadthForPositionedChild(*child
, ForRows
, rowStartIsAuto
, child
->style()->gridRowEnd().isAuto(), rowOffset
, rowBreadth
);
1417 child
->setOverrideContainingBlockContentLogicalWidth(columnBreadth
);
1418 child
->setOverrideContainingBlockContentLogicalHeight(rowBreadth
);
1419 child
->setExtraInlineOffset(columnOffset
);
1420 child
->setExtraBlockOffset(rowOffset
);
1422 if (child
->parent() == this) {
1423 // If column/row start is "auto" the static position has been already set in prepareChildForPositionedLayout().
1424 // If column/row start is not "auto" the padding has been already computed in offsetAndBreadthForPositionedChild().
1425 DeprecatedPaintLayer
* childLayer
= child
->layer();
1426 if (!columnStartIsAuto
)
1427 childLayer
->setStaticInlinePosition(borderStart() + columnOffset
);
1428 if (!rowStartIsAuto
)
1429 childLayer
->setStaticBlockPosition(borderBefore() + rowOffset
);
1433 LayoutBlock::layoutPositionedObjects(relayoutChildren
, info
);
1436 void LayoutGrid::offsetAndBreadthForPositionedChild(const LayoutBox
& child
, GridTrackSizingDirection direction
, bool startIsAuto
, bool endIsAuto
, LayoutUnit
& offset
, LayoutUnit
& breadth
)
1438 ASSERT(child
.isHorizontalWritingMode() == isHorizontalWritingMode());
1440 OwnPtr
<GridSpan
> positions
= GridResolvedPosition::resolveGridPositionsFromStyle(*style(), child
, direction
);
1442 offset
= LayoutUnit();
1443 breadth
= (direction
== ForColumns
) ? clientLogicalWidth() : clientLogicalHeight();
1447 GridResolvedPosition firstPosition
= GridResolvedPosition(0);
1448 GridResolvedPosition initialPosition
= startIsAuto
? firstPosition
: positions
->resolvedInitialPosition
;
1449 GridResolvedPosition lastPosition
= GridResolvedPosition((direction
== ForColumns
? gridColumnCount() : gridRowCount()) - 1);
1450 GridResolvedPosition finalPosition
= endIsAuto
? lastPosition
: positions
->resolvedFinalPosition
;
1452 // Positioned children do not grow the grid, so we need to clamp the positions to avoid ending up outside of it.
1453 initialPosition
= std::min
<GridResolvedPosition
>(initialPosition
, lastPosition
);
1454 finalPosition
= std::min
<GridResolvedPosition
>(finalPosition
, lastPosition
);
1456 LayoutUnit start
= startIsAuto
? LayoutUnit() : (direction
== ForColumns
) ? m_columnPositions
[initialPosition
.toInt()] : m_rowPositions
[initialPosition
.toInt()];
1457 LayoutUnit end
= endIsAuto
? (direction
== ForColumns
) ? logicalWidth() : logicalHeight() : (direction
== ForColumns
) ? m_columnPositions
[finalPosition
.next().toInt()] : m_rowPositions
[finalPosition
.next().toInt()];
1459 breadth
= end
- start
;
1462 breadth
-= (direction
== ForColumns
) ? borderStart() : borderBefore();
1464 start
-= ((direction
== ForColumns
) ? borderStart() : borderBefore());
1467 breadth
-= (direction
== ForColumns
) ? borderEnd() : borderAfter();
1468 breadth
-= scrollbarLogicalWidth();
1474 GridCoordinate
LayoutGrid::cachedGridCoordinate(const LayoutBox
& gridItem
) const
1476 ASSERT(m_gridItemCoordinate
.contains(&gridItem
));
1477 return m_gridItemCoordinate
.get(&gridItem
);
1480 LayoutUnit
LayoutGrid::gridAreaBreadthForChild(const LayoutBox
& child
, GridTrackSizingDirection direction
, const Vector
<GridTrack
>& tracks
) const
1482 const GridCoordinate
& coordinate
= cachedGridCoordinate(child
);
1483 const GridSpan
& span
= (direction
== ForColumns
) ? coordinate
.columns
: coordinate
.rows
;
1484 LayoutUnit gridAreaBreadth
= 0;
1485 for (GridSpan::iterator trackPosition
= span
.begin(); trackPosition
!= span
.end(); ++trackPosition
)
1486 gridAreaBreadth
+= tracks
[trackPosition
.toInt()].baseSize();
1487 return gridAreaBreadth
;
1490 LayoutUnit
LayoutGrid::gridAreaBreadthForChildIncludingAlignmentOffsets(const LayoutBox
& child
, GridTrackSizingDirection direction
, const GridSizingData
& sizingData
) const
1492 // We need the cached value when available because Content Distribution alignment properties
1493 // may have some influence in the final grid area breadth.
1494 const Vector
<GridTrack
>& tracks
= (direction
== ForColumns
) ? sizingData
.columnTracks
: sizingData
.rowTracks
;
1495 const GridCoordinate
& coordinate
= cachedGridCoordinate(child
);
1496 const GridSpan
& span
= (direction
== ForColumns
) ? coordinate
.columns
: coordinate
.rows
;
1497 const Vector
<LayoutUnit
>& linePositions
= (direction
== ForColumns
) ? m_columnPositions
: m_rowPositions
;
1498 LayoutUnit initialTrackPosition
= linePositions
[span
.resolvedInitialPosition
.toInt()];
1499 LayoutUnit finalTrackPosition
= linePositions
[span
.resolvedFinalPosition
.toInt()];
1500 // Track Positions vector stores the 'start' grid line of each track, so w have to add last track's baseSize.
1501 return finalTrackPosition
- initialTrackPosition
+ tracks
[span
.resolvedFinalPosition
.toInt()].baseSize();
1504 void LayoutGrid::populateGridPositions(GridSizingData
& sizingData
, LayoutUnit availableSpaceForColumns
, LayoutUnit availableSpaceForRows
)
1506 // Since we add alignment offsets, grid lines are not always adjacent. Hence we will have to
1507 // assume from now on that we just store positions of the initial grid lines of each track,
1508 // except the last one, which is the only one considered as a final grid line of a track.
1509 // FIXME: This will affect the computed style value of grid tracks size, since we are
1510 // using these positions to compute them.
1512 unsigned numberOfTracks
= sizingData
.columnTracks
.size();
1513 unsigned numberOfLines
= numberOfTracks
+ 1;
1514 unsigned lastLine
= numberOfLines
- 1;
1515 unsigned nextToLastLine
= numberOfLines
- 2;
1516 ContentAlignmentData offset
= computeContentPositionAndDistributionOffset(ForColumns
, availableSpaceForColumns
, numberOfTracks
);
1517 m_columnPositions
.resize(numberOfLines
);
1518 m_columnPositions
[0] = borderAndPaddingStart() + offset
.positionOffset
;
1519 for (unsigned i
= 0; i
< lastLine
; ++i
)
1520 m_columnPositions
[i
+ 1] = m_columnPositions
[i
] + offset
.distributionOffset
+ sizingData
.columnTracks
[i
].baseSize();
1521 m_columnPositions
[lastLine
] = m_columnPositions
[nextToLastLine
] + sizingData
.columnTracks
[nextToLastLine
].baseSize();
1523 numberOfTracks
= sizingData
.rowTracks
.size();
1524 numberOfLines
= numberOfTracks
+ 1;
1525 lastLine
= numberOfLines
- 1;
1526 nextToLastLine
= numberOfLines
- 2;
1527 offset
= computeContentPositionAndDistributionOffset(ForRows
, availableSpaceForRows
, numberOfTracks
);
1528 m_rowPositions
.resize(numberOfLines
);
1529 m_rowPositions
[0] = borderAndPaddingBefore() + offset
.positionOffset
;
1530 for (unsigned i
= 0; i
< lastLine
; ++i
)
1531 m_rowPositions
[i
+ 1] = m_rowPositions
[i
] + offset
.distributionOffset
+ sizingData
.rowTracks
[i
].baseSize();
1532 m_rowPositions
[lastLine
] = m_rowPositions
[nextToLastLine
] + sizingData
.rowTracks
[nextToLastLine
].baseSize();
1535 static LayoutUnit
computeOverflowAlignmentOffset(OverflowAlignment overflow
, LayoutUnit trackBreadth
, LayoutUnit childBreadth
)
1537 LayoutUnit offset
= trackBreadth
- childBreadth
;
1539 case OverflowAlignmentSafe
:
1540 // If overflow is 'safe', we have to make sure we don't overflow the 'start'
1541 // edge (potentially cause some data loss as the overflow is unreachable).
1542 return std::max
<LayoutUnit
>(0, offset
);
1543 case OverflowAlignmentTrue
:
1544 case OverflowAlignmentDefault
:
1545 // If we overflow our alignment container and overflow is 'true' (default), we
1546 // ignore the overflow and just return the value regardless (which may cause data
1547 // loss as we overflow the 'start' edge).
1551 ASSERT_NOT_REACHED();
1555 static inline LayoutUnit
constrainedChildIntrinsicContentLogicalHeight(const LayoutBox
& child
)
1557 LayoutUnit childIntrinsicContentLogicalHeight
= child
.intrinsicContentLogicalHeight();
1558 return child
.constrainLogicalHeightByMinMax(childIntrinsicContentLogicalHeight
+ child
.borderAndPaddingLogicalHeight(), childIntrinsicContentLogicalHeight
);
1561 // FIXME: This logic is shared by LayoutFlexibleBox, so it should be moved to LayoutBox.
1562 bool LayoutGrid::needToStretchChildLogicalHeight(const LayoutBox
& child
) const
1564 if (ComputedStyle::resolveAlignment(styleRef(), child
.styleRef(), ItemPositionStretch
) != ItemPositionStretch
)
1567 return isHorizontalWritingMode() && child
.style()->height().isAuto();
1570 // FIXME: This logic is shared by LayoutFlexibleBox, so it should be moved to LayoutBox.
1571 LayoutUnit
LayoutGrid::childIntrinsicHeight(const LayoutBox
& child
) const
1573 if (child
.isHorizontalWritingMode() && needToStretchChildLogicalHeight(child
))
1574 return constrainedChildIntrinsicContentLogicalHeight(child
);
1575 return child
.size().height();
1578 // FIXME: This logic is shared by LayoutFlexibleBox, so it should be moved to LayoutBox.
1579 LayoutUnit
LayoutGrid::childIntrinsicWidth(const LayoutBox
& child
) const
1581 if (!child
.isHorizontalWritingMode() && needToStretchChildLogicalHeight(child
))
1582 return constrainedChildIntrinsicContentLogicalHeight(child
);
1583 return child
.size().width();
1586 // FIXME: This logic is shared by LayoutFlexibleBox, so it should be moved to LayoutBox.
1587 LayoutUnit
LayoutGrid::intrinsicLogicalHeightForChild(const LayoutBox
& child
) const
1589 return isHorizontalWritingMode() ? childIntrinsicHeight(child
) : childIntrinsicWidth(child
);
1592 // FIXME: This logic is shared by LayoutFlexibleBox, so it should be moved to LayoutBox.
1593 LayoutUnit
LayoutGrid::marginLogicalHeightForChild(const LayoutBox
& child
) const
1595 return isHorizontalWritingMode() ? child
.marginHeight() : child
.marginWidth();
1598 LayoutUnit
LayoutGrid::computeMarginLogicalHeightForChild(const LayoutBox
& child
) const
1600 if (!child
.styleRef().hasMargin())
1603 LayoutUnit marginBefore
;
1604 LayoutUnit marginAfter
;
1605 child
.computeMarginsForDirection(BlockDirection
, this, child
.containingBlockLogicalWidthForContent(), child
.logicalHeight(), marginBefore
, marginAfter
,
1606 child
.style()->marginBeforeUsing(style()),
1607 child
.style()->marginAfterUsing(style()));
1609 return marginBefore
+ marginAfter
;
1612 LayoutUnit
LayoutGrid::availableAlignmentSpaceForChildBeforeStretching(LayoutUnit gridAreaBreadthForChild
, const LayoutBox
& child
) const
1614 LayoutUnit childMarginLogicalHeight
= marginLogicalHeightForChild(child
);
1616 // Because we want to avoid multiple layouts, stretching logic might be performed before
1617 // children are laid out, so we can't use the child cached values. Hence, we need to
1618 // compute margins in order to determine the available height before stretching.
1619 if (childMarginLogicalHeight
== 0)
1620 childMarginLogicalHeight
= computeMarginLogicalHeightForChild(child
);
1622 return gridAreaBreadthForChild
- childMarginLogicalHeight
;
1625 // FIXME: This logic is shared by LayoutFlexibleBox, so it should be moved to LayoutBox.
1626 void LayoutGrid::applyStretchAlignmentToChildIfNeeded(LayoutBox
& child
)
1628 // We clear both width and height override values because we will decide now whether they
1629 // are allowed or not, evaluating the conditions which might have changed since the old
1631 child
.clearOverrideSize();
1633 auto& childStyle
= child
.styleRef();
1634 bool isHorizontalMode
= isHorizontalWritingMode();
1635 bool hasAutoSizeInRowAxis
= isHorizontalMode
? childStyle
.width().isAuto() : childStyle
.height().isAuto();
1636 bool allowedToStretchChildAlongRowAxis
= hasAutoSizeInRowAxis
&& !childStyle
.marginStartUsing(style()).isAuto() && !childStyle
.marginEndUsing(style()).isAuto();
1637 if (!allowedToStretchChildAlongRowAxis
|| ComputedStyle::resolveJustification(styleRef(), childStyle
, ItemPositionStretch
) != ItemPositionStretch
) {
1638 bool hasAutoMinSizeInRowAxis
= isHorizontalMode
? childStyle
.minWidth().isAuto() : childStyle
.minHeight().isAuto();
1639 bool canShrinkToFitInRowAxisForChild
= !hasAutoMinSizeInRowAxis
|| child
.minPreferredLogicalWidth() <= child
.overrideContainingBlockContentLogicalWidth();
1640 // TODO(lajava): how to handle orthogonality in this case ?.
1641 // TODO(lajava): grid track sizing and positioning do not support orthogonal modes yet.
1642 if (hasAutoSizeInRowAxis
&& canShrinkToFitInRowAxisForChild
) {
1643 LayoutUnit childWidthToFitContent
= std::max(std::min(child
.maxPreferredLogicalWidth(), child
.overrideContainingBlockContentLogicalWidth() - child
.marginLogicalWidth()), child
.minPreferredLogicalWidth());
1644 LayoutUnit desiredLogicalWidth
= child
.constrainLogicalHeightByMinMax(childWidthToFitContent
, -1);
1645 child
.setOverrideLogicalContentWidth(desiredLogicalWidth
- child
.borderAndPaddingLogicalWidth());
1646 if (desiredLogicalWidth
!= child
.logicalWidth())
1647 child
.setNeedsLayout(LayoutInvalidationReason::GridChanged
);
1651 bool hasAutoSizeInColumnAxis
= isHorizontalMode
? childStyle
.height().isAuto() : childStyle
.width().isAuto();
1652 bool allowedToStretchChildAlongColumnAxis
= hasAutoSizeInColumnAxis
&& !childStyle
.marginBeforeUsing(style()).isAuto() && !childStyle
.marginAfterUsing(style()).isAuto();
1653 if (allowedToStretchChildAlongColumnAxis
&& ComputedStyle::resolveAlignment(styleRef(), childStyle
, ItemPositionStretch
) == ItemPositionStretch
) {
1654 // TODO (lajava): If the child has orthogonal flow, then it already has an override height set, so use it.
1655 // TODO (lajava): grid track sizing and positioning do not support orthogonal modes yet.
1656 if (child
.isHorizontalWritingMode() == isHorizontalMode
) {
1657 LayoutUnit stretchedLogicalHeight
= availableAlignmentSpaceForChildBeforeStretching(child
.overrideContainingBlockContentLogicalHeight(), child
);
1658 LayoutUnit desiredLogicalHeight
= child
.constrainLogicalHeightByMinMax(stretchedLogicalHeight
, -1);
1659 child
.setOverrideLogicalContentHeight(desiredLogicalHeight
- child
.borderAndPaddingLogicalHeight());
1660 if (desiredLogicalHeight
!= child
.logicalHeight()) {
1661 // TODO (lajava): Can avoid laying out here in some cases. See https://webkit.org/b/87905.
1662 child
.setLogicalHeight(0);
1663 child
.setNeedsLayout(LayoutInvalidationReason::GridChanged
);
1669 GridAxisPosition
LayoutGrid::columnAxisPositionForChild(const LayoutBox
& child
) const
1671 bool hasOrthogonalWritingMode
= child
.isHorizontalWritingMode() != isHorizontalWritingMode();
1672 bool hasSameWritingMode
= child
.styleRef().writingMode() == styleRef().writingMode();
1674 switch (ComputedStyle::resolveAlignment(styleRef(), child
.styleRef(), ItemPositionStretch
)) {
1675 case ItemPositionSelfStart
:
1676 // If orthogonal writing-modes, this computes to 'start'.
1677 // FIXME: grid track sizing and positioning do not support orthogonal modes yet.
1678 // 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.
1679 return (hasOrthogonalWritingMode
|| hasSameWritingMode
) ? GridAxisStart
: GridAxisEnd
;
1680 case ItemPositionSelfEnd
:
1681 // If orthogonal writing-modes, this computes to 'end'.
1682 // FIXME: grid track sizing and positioning do not support orthogonal modes yet.
1683 // 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.
1684 return (hasOrthogonalWritingMode
|| hasSameWritingMode
) ? GridAxisEnd
: GridAxisStart
;
1685 case ItemPositionLeft
:
1686 // The alignment axis (column axis) and the inline axis are parallell in
1687 // orthogonal writing mode. Otherwise this this is equivalent to 'start'.
1688 // FIXME: grid track sizing and positioning do not support orthogonal modes yet.
1689 return GridAxisStart
;
1690 case ItemPositionRight
:
1691 // The alignment axis (column axis) and the inline axis are parallell in
1692 // orthogonal writing mode. Otherwise this this is equivalent to 'start'.
1693 // FIXME: grid track sizing and positioning do not support orthogonal modes yet.
1694 return hasOrthogonalWritingMode
? GridAxisEnd
: GridAxisStart
;
1695 case ItemPositionCenter
:
1696 return GridAxisCenter
;
1697 case ItemPositionFlexStart
: // Only used in flex layout, otherwise equivalent to 'start'.
1698 case ItemPositionStart
:
1699 return GridAxisStart
;
1700 case ItemPositionFlexEnd
: // Only used in flex layout, otherwise equivalent to 'end'.
1701 case ItemPositionEnd
:
1703 case ItemPositionStretch
:
1704 return GridAxisStart
;
1705 case ItemPositionBaseline
:
1706 case ItemPositionLastBaseline
:
1707 // FIXME: These two require implementing Baseline Alignment. For now, we always 'start' align the child.
1709 return GridAxisStart
;
1710 case ItemPositionAuto
:
1714 ASSERT_NOT_REACHED();
1715 return GridAxisStart
;
1718 GridAxisPosition
LayoutGrid::rowAxisPositionForChild(const LayoutBox
& child
) const
1720 bool hasOrthogonalWritingMode
= child
.isHorizontalWritingMode() != isHorizontalWritingMode();
1721 bool hasSameDirection
= child
.styleRef().direction() == styleRef().direction();
1722 bool isLTR
= styleRef().isLeftToRightDirection();
1724 switch (ComputedStyle::resolveJustification(styleRef(), child
.styleRef(), ItemPositionStretch
)) {
1725 case ItemPositionSelfStart
:
1726 // For orthogonal writing-modes, this computes to 'start'
1727 // FIXME: grid track sizing and positioning do not support orthogonal modes yet.
1728 // self-start is based on the child's direction. That's why we need to check against the grid container's direction.
1729 return (hasOrthogonalWritingMode
|| hasSameDirection
) ? GridAxisStart
: GridAxisEnd
;
1730 case ItemPositionSelfEnd
:
1731 // For orthogonal writing-modes, this computes to 'start'
1732 // FIXME: grid track sizing and positioning do not support orthogonal modes yet.
1733 return (hasOrthogonalWritingMode
|| hasSameDirection
) ? GridAxisEnd
: GridAxisStart
;
1734 case ItemPositionLeft
:
1735 return isLTR
? GridAxisStart
: GridAxisEnd
;
1736 case ItemPositionRight
:
1737 return isLTR
? GridAxisEnd
: GridAxisStart
;
1738 case ItemPositionCenter
:
1739 return GridAxisCenter
;
1740 case ItemPositionFlexStart
: // Only used in flex layout, otherwise equivalent to 'start'.
1741 case ItemPositionStart
:
1742 return GridAxisStart
;
1743 case ItemPositionFlexEnd
: // Only used in flex layout, otherwise equivalent to 'end'.
1744 case ItemPositionEnd
:
1746 case ItemPositionStretch
:
1747 return GridAxisStart
;
1748 case ItemPositionBaseline
:
1749 case ItemPositionLastBaseline
:
1750 // FIXME: These two require implementing Baseline Alignment. For now, we always 'start' align the child.
1752 return GridAxisStart
;
1753 case ItemPositionAuto
:
1757 ASSERT_NOT_REACHED();
1758 return GridAxisStart
;
1761 LayoutUnit
LayoutGrid::columnAxisOffsetForChild(const LayoutBox
& child
) const
1763 const GridCoordinate
& coordinate
= cachedGridCoordinate(child
);
1764 LayoutUnit startOfRow
= m_rowPositions
[coordinate
.rows
.resolvedInitialPosition
.toInt()];
1765 LayoutUnit startPosition
= startOfRow
+ marginBeforeForChild(child
);
1766 GridAxisPosition axisPosition
= columnAxisPositionForChild(child
);
1767 switch (axisPosition
) {
1769 return startPosition
;
1771 case GridAxisCenter
: {
1772 LayoutUnit endOfRow
= m_rowPositions
[coordinate
.rows
.resolvedFinalPosition
.next().toInt()];
1773 LayoutUnit offsetFromStartPosition
= computeOverflowAlignmentOffset(child
.styleRef().alignSelfOverflowAlignment(), endOfRow
- startOfRow
, child
.logicalHeight() + child
.marginLogicalHeight());
1774 return startPosition
+ (axisPosition
== GridAxisEnd
? offsetFromStartPosition
: offsetFromStartPosition
/ 2);
1778 ASSERT_NOT_REACHED();
1782 LayoutUnit
LayoutGrid::rowAxisOffsetForChild(const LayoutBox
& child
) const
1784 const GridCoordinate
& coordinate
= cachedGridCoordinate(child
);
1785 LayoutUnit startOfColumn
= m_columnPositions
[coordinate
.columns
.resolvedInitialPosition
.toInt()];
1786 LayoutUnit startPosition
= startOfColumn
+ marginStartForChild(child
);
1787 GridAxisPosition axisPosition
= rowAxisPositionForChild(child
);
1788 switch (axisPosition
) {
1790 return startPosition
;
1792 case GridAxisCenter
: {
1793 LayoutUnit endOfColumn
= m_columnPositions
[coordinate
.columns
.resolvedFinalPosition
.next().toInt()];
1794 LayoutUnit offsetFromStartPosition
= computeOverflowAlignmentOffset(child
.styleRef().justifySelfOverflowAlignment(), endOfColumn
- startOfColumn
, child
.logicalWidth() + child
.marginLogicalWidth());
1795 return startPosition
+ (axisPosition
== GridAxisEnd
? offsetFromStartPosition
: offsetFromStartPosition
/ 2);
1799 ASSERT_NOT_REACHED();
1803 ContentPosition
static resolveContentDistributionFallback(ContentDistributionType distribution
)
1805 switch (distribution
) {
1806 case ContentDistributionSpaceBetween
:
1807 return ContentPositionStart
;
1808 case ContentDistributionSpaceAround
:
1809 return ContentPositionCenter
;
1810 case ContentDistributionSpaceEvenly
:
1811 return ContentPositionCenter
;
1812 case ContentDistributionStretch
:
1813 return ContentPositionStart
;
1814 case ContentDistributionDefault
:
1815 return ContentPositionAuto
;
1818 ASSERT_NOT_REACHED();
1819 return ContentPositionAuto
;
1822 static inline LayoutUnit
offsetToStartEdge(bool isLeftToRight
, LayoutUnit availableSpace
)
1824 return isLeftToRight
? LayoutUnit() : availableSpace
;
1827 static inline LayoutUnit
offsetToEndEdge(bool isLeftToRight
, LayoutUnit availableSpace
)
1829 return !isLeftToRight
? LayoutUnit() : availableSpace
;
1833 static ContentAlignmentData
contentDistributionOffset(LayoutUnit availableFreeSpace
, ContentPosition
& fallbackPosition
, ContentDistributionType distribution
, unsigned numberOfGridTracks
)
1835 if (distribution
!= ContentDistributionDefault
&& fallbackPosition
== ContentPositionAuto
)
1836 fallbackPosition
= resolveContentDistributionFallback(distribution
);
1838 if (availableFreeSpace
<= 0)
1841 LayoutUnit distributionOffset
;
1842 switch (distribution
) {
1843 case ContentDistributionSpaceBetween
:
1844 if (numberOfGridTracks
< 2)
1846 return {0, availableFreeSpace
/ (numberOfGridTracks
- 1)};
1847 case ContentDistributionSpaceAround
:
1848 if (numberOfGridTracks
< 1)
1850 distributionOffset
= availableFreeSpace
/ numberOfGridTracks
;
1851 return {distributionOffset
/ 2, distributionOffset
};
1852 case ContentDistributionSpaceEvenly
:
1853 distributionOffset
= availableFreeSpace
/ (numberOfGridTracks
+ 1);
1854 return {distributionOffset
, distributionOffset
};
1855 case ContentDistributionStretch
:
1857 case ContentDistributionDefault
:
1861 ASSERT_NOT_REACHED();
1865 ContentAlignmentData
LayoutGrid::computeContentPositionAndDistributionOffset(GridTrackSizingDirection direction
, LayoutUnit availableFreeSpace
, unsigned numberOfGridTracks
) const
1867 bool isRowAxis
= direction
== ForColumns
;
1868 ContentPosition position
= isRowAxis
? styleRef().justifyContentPosition() : styleRef().alignContentPosition();
1869 ContentDistributionType distribution
= isRowAxis
? styleRef().justifyContentDistribution() : styleRef().alignContentDistribution();
1870 // If <content-distribution> value can't be applied, 'position' will become the associated
1871 // <content-position> fallback value.
1872 ContentAlignmentData contentAlignment
= contentDistributionOffset(availableFreeSpace
, position
, distribution
, numberOfGridTracks
);
1873 if (contentAlignment
.isValid())
1874 return contentAlignment
;
1876 OverflowAlignment overflow
= isRowAxis
? styleRef().justifyContentOverflowAlignment() : styleRef().alignContentOverflowAlignment();
1877 if (availableFreeSpace
<= 0 && overflow
== OverflowAlignmentSafe
)
1881 case ContentPositionLeft
:
1882 // The align-content's axis is always orthogonal to the inline-axis.
1884 case ContentPositionRight
:
1886 return {availableFreeSpace
, 0};
1887 // The align-content's axis is always orthogonal to the inline-axis.
1889 case ContentPositionCenter
:
1890 return {availableFreeSpace
/ 2, 0};
1891 case ContentPositionFlexEnd
: // Only used in flex layout, for other layout, it's equivalent to 'End'.
1892 case ContentPositionEnd
:
1894 return {offsetToEndEdge(styleRef().isLeftToRightDirection(), availableFreeSpace
), 0};
1895 return {availableFreeSpace
, 0};
1896 case ContentPositionFlexStart
: // Only used in flex layout, for other layout, it's equivalent to 'Start'.
1897 case ContentPositionStart
:
1899 return {offsetToStartEdge(styleRef().isLeftToRightDirection(), availableFreeSpace
), 0};
1901 case ContentPositionBaseline
:
1902 case ContentPositionLastBaseline
:
1903 // FIXME: These two require implementing Baseline Alignment. For now, we always 'start' align the child.
1906 return {offsetToStartEdge(styleRef().isLeftToRightDirection(), availableFreeSpace
), 0};
1908 case ContentPositionAuto
:
1912 ASSERT_NOT_REACHED();
1916 LayoutPoint
LayoutGrid::findChildLogicalPosition(const LayoutBox
& child
, GridSizingData
& sizingData
) const
1918 LayoutUnit rowAxisOffset
= rowAxisOffsetForChild(child
);
1919 // We stored m_columnPosition s's data ignoring the direction, hence we might need now
1920 // to translate positions from RTL to LTR, as it's more convenient for painting.
1921 if (!style()->isLeftToRightDirection()) {
1922 LayoutUnit alignmentOffset
= m_columnPositions
[0] - borderAndPaddingStart();
1923 LayoutUnit rightGridEdgePosition
= m_columnPositions
[m_columnPositions
.size() - 1] + alignmentOffset
+ borderAndPaddingLogicalLeft();
1924 rowAxisOffset
= rightGridEdgePosition
- (rowAxisOffset
+ child
.logicalWidth());
1927 return LayoutPoint(rowAxisOffset
, columnAxisOffsetForChild(child
));
1930 void LayoutGrid::paintChildren(const PaintInfo
& paintInfo
, const LayoutPoint
& paintOffset
)
1932 GridPainter(*this).paintChildren(paintInfo
, paintOffset
);
1935 } // namespace blink