Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fork out Masonry into a separate layout function #9410

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 0 additions & 1 deletion Source/WebCore/rendering/GridMasonryLayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ void GridMasonryLayout::collectMasonryItems()
else
m_itemsWithIndefiniteGridAxisPosition.append(child);
}

}
}

Expand Down
6 changes: 6 additions & 0 deletions Source/WebCore/rendering/GridTrackSizingAlgorithm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ void GridTrack::setGrowthLimitCap(std::optional<LayoutUnit> growthLimitCap)
m_growthLimitCap = growthLimitCap;
}

const GridTrackSize& GridTrack::cachedTrackSize() const
{
RELEASE_ASSERT(m_cachedTrackSize);
return *m_cachedTrackSize;
}

void GridTrack::setCachedTrackSize(const GridTrackSize& cachedTrackSize)
{
m_cachedTrackSize = cachedTrackSize;
Expand Down
6 changes: 1 addition & 5 deletions Source/WebCore/rendering/GridTrackSizingAlgorithm.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,7 @@ class GridTrack {
void setGrowthLimitCap(std::optional<LayoutUnit>);
std::optional<LayoutUnit> growthLimitCap() const { return m_growthLimitCap; }

const GridTrackSize& cachedTrackSize() const
{
RELEASE_ASSERT(m_cachedTrackSize);
return *m_cachedTrackSize;
}
const GridTrackSize& cachedTrackSize() const;
void setCachedTrackSize(const GridTrackSize&);

private:
Expand Down
141 changes: 136 additions & 5 deletions Source/WebCore/rendering/RenderGrid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,138 @@ void RenderGrid::layoutBlock(bool relayoutChildren, LayoutUnit)
if (!relayoutChildren && simplifiedLayout())
return;

// The layoutBlock was handling the layout of both the grid and masonry implementations.
// This caused a huge amount of branching code to handle masonry specific cases. Splitting up the code
// to layout will simplify both implementations.
if (!isMasonry())
layoutGrid(relayoutChildren);
else
layoutMasonry(relayoutChildren);
}

void RenderGrid::layoutGrid(bool relayoutChildren)
{
LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
{
LayoutStateMaintainer statePusher(*this, locationOffset(), isTransformed() || hasReflection() || style().isFlippedBlocksWritingMode());

preparePaginationBeforeBlockLayout(relayoutChildren);
beginUpdateScrollInfoAfterLayoutTransaction();

LayoutSize previousSize = size();

// FIXME: We should use RenderBlock::hasDefiniteLogicalHeight() only but it does not work for positioned stuff.
// FIXME: Consider caching the hasDefiniteLogicalHeight value throughout the layout.
// FIXME: We might need to cache the hasDefiniteLogicalHeight if the call of RenderBlock::hasDefiniteLogicalHeight() causes a relevant performance regression.
bool hasDefiniteLogicalHeight = RenderBlock::hasDefiniteLogicalHeight() || hasOverridingLogicalHeight() || computeContentLogicalHeight(MainOrPreferredSize, style().logicalHeight(), std::nullopt);

auto aspectRatioBlockSizeDependentGridItems = computeAspectRatioDependentAndBaselineItems();

resetLogicalHeightBeforeLayoutIfNeeded();

// Fieldsets need to find their legend and position it inside the border of the object.
// The legend then gets skipped during normal layout. The same is true for ruby text.
// It doesn't get included in the normal layout process but is instead skipped.
layoutExcludedChildren(relayoutChildren);

updateLogicalWidth();

LayoutUnit availableSpaceForColumns = availableLogicalWidth();
placeItemsOnGrid(availableSpaceForColumns);

m_trackSizingAlgorithm.setAvailableSpace(ForColumns, availableSpaceForColumns);
performGridItemsPreLayout(m_trackSizingAlgorithm);

// 1- First, the track sizing algorithm is used to resolve the sizes of the grid columns. At this point the
// logical width is always definite as the above call to updateLogicalWidth() properly resolves intrinsic
// sizes. We cannot do the same for heights though because many code paths inside updateLogicalHeight() require
// a previous call to setLogicalHeight() to resolve heights properly (like for positioned items for example).
computeTrackSizesForDefiniteSize(ForColumns, availableSpaceForColumns);

// 1.5- Compute Content Distribution offsets for column tracks
computeContentPositionAndDistributionOffset(ForColumns, m_trackSizingAlgorithm.freeSpace(ForColumns).value(), nonCollapsedTracks(ForColumns));

// 2- Next, the track sizing algorithm resolves the sizes of the grid rows,
// using the grid column sizes calculated in the previous step.
bool shouldRecomputeHeight = false;
if (!hasDefiniteLogicalHeight) {
computeTrackSizesForIndefiniteSize(m_trackSizingAlgorithm, ForRows);
if (shouldApplySizeContainment())
shouldRecomputeHeight = true;
} else
computeTrackSizesForDefiniteSize(ForRows, availableLogicalHeight(ExcludeMarginBorderPadding));

LayoutUnit trackBasedLogicalHeight = borderAndPaddingLogicalHeight() + scrollbarLogicalHeight();
if (auto size = explicitIntrinsicInnerLogicalSize(ForRows))
trackBasedLogicalHeight += size.value();
else
trackBasedLogicalHeight += m_trackSizingAlgorithm.computeTrackBasedSize();

if (shouldRecomputeHeight)
computeTrackSizesForDefiniteSize(ForRows, trackBasedLogicalHeight);

setLogicalHeight(trackBasedLogicalHeight);

updateLogicalHeight();

// Once grid's indefinite height is resolved, we can compute the
// available free space for Content Alignment.
if (!hasDefiniteLogicalHeight)
m_trackSizingAlgorithm.setFreeSpace(ForRows, logicalHeight() - trackBasedLogicalHeight);

// 2.5- Compute Content Distribution offsets for rows tracks
computeContentPositionAndDistributionOffset(ForRows, m_trackSizingAlgorithm.freeSpace(ForRows).value(), nonCollapsedTracks(ForRows));

if (!aspectRatioBlockSizeDependentGridItems.isEmpty()) {
updateGridAreaForAspectRatioItems(aspectRatioBlockSizeDependentGridItems);
updateLogicalWidth();
}

// 3- If the min-content contribution of any grid items have changed based on the row
// sizes calculated in step 2, steps 1 and 2 are repeated with the new min-content
// contribution (once only).
repeatTracksSizingIfNeeded(availableSpaceForColumns, contentLogicalHeight());

// Grid container should have the minimum height of a line if it's editable. That does not affect track sizing though.
if (hasLineIfEmpty()) {
LayoutUnit minHeightForEmptyLine = borderAndPaddingLogicalHeight()
+ lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes)
+ scrollbarLogicalHeight();
setLogicalHeight(std::max(logicalHeight(), minHeightForEmptyLine));
}

layoutGridItems();

endAndCommitUpdateScrollInfoAfterLayoutTransaction();

if (size() != previousSize)
relayoutChildren = true;

m_outOfFlowItemColumn.clear();
m_outOfFlowItemRow.clear();

layoutPositionedObjects(relayoutChildren || isDocumentElementRenderer());
m_trackSizingAlgorithm.reset();

computeOverflow(layoutOverflowLogicalBottom(*this));
}

updateLayerTransform();

// Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
// we overflow or not.
updateScrollInfoAfterLayout();

repainter.repaintAfterLayout();

clearNeedsLayout();

m_trackSizingAlgorithm.clearBaselineItemsCache();
m_baselineItemsCached = false;
}

void RenderGrid::layoutMasonry(bool relayoutChildren)
{
LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
{
LayoutStateMaintainer statePusher(*this, locationOffset(), isTransformed() || hasReflection() || style().isFlippedBlocksWritingMode());
Expand Down Expand Up @@ -293,9 +425,9 @@ void RenderGrid::layoutBlock(bool relayoutChildren, LayoutUnit)
m_trackSizingAlgorithm.setAvailableSpace(ForColumns, availableSpaceForColumns);
performGridItemsPreLayout(m_trackSizingAlgorithm);

// 1- First, the track sizing algorithm is used to resolve the sizes of the grid columns. At this point the
// logical width is always definite as the above call to updateLogicalWidth() properly resolves intrinsic
// sizes. We cannot do the same for heights though because many code paths inside updateLogicalHeight() require
// 1- First, the track sizing algorithm is used to resolve the sizes of the grid columns. At this point the
// logical width is always definite as the above call to updateLogicalWidth() properly resolves intrinsic
// sizes. We cannot do the same for heights though because many code paths inside updateLogicalHeight() require
// a previous call to setLogicalHeight() to resolve heights properly (like for positioned items for example).
computeTrackSizesForDefiniteSize(ForColumns, availableSpaceForColumns);

Expand Down Expand Up @@ -330,7 +462,7 @@ void RenderGrid::layoutBlock(bool relayoutChildren, LayoutUnit)
else {
if (areMasonryRows())
trackBasedLogicalHeight += m_masonryLayout.gridContentSize() + m_masonryLayout.gridGap();
else
else
trackBasedLogicalHeight += m_trackSizingAlgorithm.computeTrackBasedSize();
}
if (shouldRecomputeHeight)
Expand All @@ -353,7 +485,6 @@ void RenderGrid::layoutBlock(bool relayoutChildren, LayoutUnit)
updateLogicalWidth();
}


// 3- If the min-content contribution of any grid items have changed based on the row
// sizes calculated in step 2, steps 1 and 2 are repeated with the new min-content
// contribution (once only).
Expand Down
7 changes: 7 additions & 0 deletions Source/WebCore/rendering/RenderGrid.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@ class RenderGrid final : public RenderBlock {

StyleContentAlignmentData contentAlignment(GridTrackSizingDirection) const;

// These functions handle the actual implementation of layoutBlock based on if
// the grid is a standard grid or a masonry one. While masonry is an extension of grid,
// keeping the logic in the same function was leading to a messy amount of if statements being added to handle
// specific masonry cases.
void layoutGrid(bool);
void layoutMasonry(bool);

// Computes the span relative to this RenderGrid, even if the RenderBox is a child
// of a descendant subgrid.
GridSpan gridSpanForChild(const RenderBox&, GridTrackSizingDirection) const;
Expand Down