blob: 551151f3c2cb9d177b84fa84be949d227099e86b [file] [log] [blame]
/*
* Copyright (C) 2011, 2022 Apple Inc. All rights reserved.
* Copyright (C) 2013-2017 Igalia S.L.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include "Grid.h"
#include "GridMasonryLayout.h"
#include "GridTrackSizingAlgorithm.h"
#include "RenderBlock.h"
#include "StyleGridTrackSizingDirection.h"
#include <wtf/TZoneMalloc.h>
namespace WTF {
template<typename T>
class Range;
}
namespace WebCore {
namespace LayoutIntegration {
class GridLayout;
}
class GridArea;
class GridLayoutState;
class GridSpan;
class LayoutRange;
struct ContentAlignmentData {
LayoutUnit positionOffset;
LayoutUnit distributionOffset;
};
enum class GridAxisPosition : uint8_t { GridAxisStart, GridAxisEnd, GridAxisCenter };
enum class SubgridDidChange : bool { No, Yes };
class GridItemSizeCache {
public:
void setSizeForGridItem(const RenderBox& gridItem, LayoutUnit size);
std::optional<LayoutUnit> sizeForItem(const RenderBox& gridItem) const;
void invalidateSizeForItem(const RenderBox& gridItem);
private:
SingleThreadWeakHashMap<const RenderBox, std::optional<LayoutUnit>> m_sizes;
};
class RenderGrid final : public RenderBlock {
WTF_MAKE_TZONE_ALLOCATED(RenderGrid);
WTF_OVERRIDE_DELETE_FOR_CHECKED_PTR(RenderGrid);
public:
RenderGrid(Element&, RenderStyle&&);
virtual ~RenderGrid();
Element& element() const { return downcast<Element>(nodeForNonAnonymous()); }
void styleDidChange(Style::Difference, const RenderStyle* oldStyle) override;
void layoutBlock(RelayoutChildren, LayoutUnit pageLogicalHeight = 0_lu) override;
bool canDropAnonymousBlockChild() const override { return false; }
bool isComputingTrackSizes() const { return m_isComputingTrackSizes; }
bool hasDefiniteLogicalHeight() const;
const std::optional<LayoutUnit> availableLogicalHeightForContentBox() const;
void setNeedsItemPlacement(SubgridDidChange descendantSubgridsNeedItemPlacement = SubgridDidChange::No);
Vector<LayoutUnit> trackSizesForComputedStyle(Style::GridTrackSizingDirection) const;
const Vector<LayoutUnit>& columnPositions() const { return m_columnPositions; }
const Vector<LayoutUnit>& rowPositions() const { return m_rowPositions; }
const Vector<LayoutUnit>& positions(Style::GridTrackSizingDirection direction) const { return direction == Style::GridTrackSizingDirection::Columns ? columnPositions() : rowPositions(); }
unsigned autoRepeatCountForDirection(Style::GridTrackSizingDirection direction) const { return currentGrid().autoRepeatTracks(direction); }
unsigned explicitGridStartForDirection(Style::GridTrackSizingDirection direction) const { return currentGrid().explicitGridStart(direction); }
// Required by GridTrackSizingAlgorithm. Keep them under control.
LayoutUnit guttersSize(Style::GridTrackSizingDirection, unsigned startLine, unsigned span, std::optional<LayoutUnit> availableSize) const;
LayoutUnit gridItemOffset(Style::GridTrackSizingDirection) const;
std::optional<LayoutUnit> explicitIntrinsicInnerLogicalSize(Style::GridTrackSizingDirection) const;
void updateGridAreaLogicalSize(RenderBox&, std::optional<LayoutUnit> width, std::optional<LayoutUnit> height) const;
bool isBaselineAlignmentForGridItem(const RenderBox&) const;
bool isBaselineAlignmentForGridItem(const RenderBox& gridItem, Style::GridTrackSizingDirection alignmentContext) const;
StyleContentAlignmentData contentAlignment(Style::GridTrackSizingDirection) const;
StyleSelfAlignmentData selfAlignmentForGridItem(const RenderBox&, LogicalBoxAxis containingAxis, StretchingMode = StretchingMode::Normal, const RenderStyle* = nullptr) const;
bool willStretchItem(const RenderBox& item, LogicalBoxAxis containingAxis, StretchingMode = StretchingMode::Normal) const override;
// 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(RelayoutChildren);
void layoutMasonry(RelayoutChildren);
// Computes the span relative to this RenderGrid, even if the RenderBox is a grid item
// of a descendant subgrid.
GridSpan gridSpanForGridItem(const RenderBox&, Style::GridTrackSizingDirection) const;
bool isSubgrid() const;
bool isSubgrid(Style::GridTrackSizingDirection) const;
bool isSubgridRows() const { return isSubgrid(Style::GridTrackSizingDirection::Rows); }
bool isSubgridColumns() const { return isSubgrid(Style::GridTrackSizingDirection::Columns); }
bool isSubgridInParentDirection(Style::GridTrackSizingDirection parentDirection) const;
// Returns true if this grid is inheriting subgridded tracks for
// the given direction from the specified ancestor. This handles
// nested subgrids, where ancestor may not be our direct parent.
bool isSubgridOf(Style::GridTrackSizingDirection, const RenderGrid& ancestor) const;
bool isMasonry() const;
bool isMasonry(Style::GridTrackSizingDirection) const;
bool isMasonry(LogicalBoxAxis axis) const { return isMasonry(Style::gridTrackSizingDirection(axis)); }
bool areMasonryRows() const { return isMasonry(Style::GridTrackSizingDirection::Rows); }
bool areMasonryColumns() const { return isMasonry(Style::GridTrackSizingDirection::Columns); }
const Grid& currentGrid() const;
Grid& currentGrid();
unsigned numTracks(Style::GridTrackSizingDirection) const;
void placeItems();
std::optional<LayoutUnit> availableSpaceForGutters(Style::GridTrackSizingDirection) const;
LayoutUnit gridGap(Style::GridTrackSizingDirection) const;
LayoutUnit gridGap(Style::GridTrackSizingDirection, std::optional<LayoutUnit> availableSize) const;
LayoutUnit masonryContentSize() const;
void updateIntrinsicLogicalHeightsForRowSizingFirstPassCacheAvailability();
std::optional<GridItemSizeCache>& intrinsicLogicalHeightsForRowSizingFirstPass() const;
bool shouldCheckExplicitIntrinsicInnerLogicalSize(Style::GridTrackSizingDirection) const;
// Checks both the grid container and the grid since the grid container is sized
// according to the rules of the formatting context it lives in while the size of the
// grid is determined by the lines/grid areas which come from track sizing.
bool isExtrinsicallySized() const;
private:
friend class GridTrackSizingAlgorithm;
friend class GridTrackSizingAlgorithmStrategy;
friend class GridMasonryLayout;
friend class PositionedLayoutConstraints;
inline void updateGridAreaWithEstimate(RenderBox& gridItem, const GridTrackSizingAlgorithm&) const;
inline void updateGridAreaIncludingAlignment(RenderBox& gridItem) const;
void computeLayoutRequirementsForItemsBeforeLayout(GridLayoutState&) const;
bool canSetColumnAxisStretchRequirementForItem(const RenderBox&) const;
ASCIILiteral renderName() const override;
void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const override;
bool selfAlignmentChangedToStretch(LogicalBoxAxis containingAxis, const RenderStyle& oldStyle, const RenderStyle& newStyle, const RenderBox& gridItem) const;
bool selfAlignmentChangedFromStretch(LogicalBoxAxis containingAxis, const RenderStyle& oldStyle, const RenderStyle& newStyle, const RenderBox& gridItem) const;
SubgridDidChange subgridDidChange(const RenderStyle& oldStyle) const;
bool explicitGridDidResize(const RenderStyle&) const;
bool namedGridLinesDefinitionDidChange(const RenderStyle&) const;
bool implicitGridLinesDefinitionDidChange(const RenderStyle&) const;
unsigned computeAutoRepeatTracksCount(Style::GridTrackSizingDirection, std::optional<LayoutUnit> availableSize) const;
unsigned clampAutoRepeatTracks(Style::GridTrackSizingDirection, unsigned autoRepeatTracks) const;
WTF::Range<size_t> autoRepeatTracksRange(Style::GridTrackSizingDirection) const;
std::unique_ptr<OrderedTrackIndexSet> computeEmptyTracksForAutoRepeat(Style::GridTrackSizingDirection) const;
enum class ShouldUpdateGridAreaLogicalSize : bool { No, Yes };
void performPreLayoutForGridItems(const GridTrackSizingAlgorithm&, const ShouldUpdateGridAreaLogicalSize) const;
void placeItemsOnGrid(std::optional<LayoutUnit> availableLogicalWidth);
void populateExplicitGridAndOrderIterator();
GridArea createEmptyGridAreaAtSpecifiedPositionsOutsideGrid(const RenderBox&, Style::GridTrackSizingDirection, const GridSpan&) const;
bool isPlacedWithinExtrinsicallySizedExplicitTracks(const RenderBox&) const;
void placeSpecifiedMajorAxisItemsOnGrid(const Vector<RenderBox*>&);
void placeAutoMajorAxisItemsOnGrid(const Vector<RenderBox*>&);
typedef std::pair<unsigned, unsigned> AutoPlacementCursor;
void placeAutoMajorAxisItemOnGrid(RenderBox&, AutoPlacementCursor&);
Style::GridTrackSizingDirection autoPlacementMajorAxisDirection() const;
Style::GridTrackSizingDirection autoPlacementMinorAxisDirection() const;
static bool itemGridAreaIsWithinImplicitGrid(const GridArea& area, unsigned gridAxisLinesCount, Style::GridTrackSizingDirection gridAxisDirection)
{
auto itemSpan = area.span(gridAxisDirection);
return itemSpan.startLine() < gridAxisLinesCount && itemSpan.endLine() < gridAxisLinesCount;
}
bool canPerformSimplifiedLayout() const final;
void prepareGridItemForPositionedLayout(RenderBox&);
bool hasStaticPositionForGridItem(const RenderBox&, Style::GridTrackSizingDirection) const;
void layoutOutOfFlowBox(RenderBox&, RelayoutChildren, bool fixedPositionObjectsOnly) override;
void computeTrackSizesForDefiniteSize(Style::GridTrackSizingDirection, LayoutUnit availableSpace, GridLayoutState&);
void computeTrackSizesForIndefiniteSize(GridTrackSizingAlgorithm&, Style::GridTrackSizingDirection, GridLayoutState&, LayoutUnit* minIntrinsicSize = nullptr, LayoutUnit* maxIntrinsicSize = nullptr) const;
LayoutUnit computeTrackBasedLogicalHeight() const;
void repeatTracksSizingIfNeeded(LayoutUnit availableSpaceForColumns, LayoutUnit availableSpaceForRows, GridLayoutState&);
void updateGridAreaForAspectRatioItems(const Vector<RenderBox*>&, GridLayoutState&);
void layoutGridItems(GridLayoutState&);
void layoutMasonryItems(GridLayoutState&);
void populateGridPositionsForDirection(const GridTrackSizingAlgorithm&, Style::GridTrackSizingDirection);
LayoutRange gridAreaRangeForOutOfFlow(const RenderBox&, Style::GridTrackSizingDirection) const;
std::pair<LayoutUnit, LayoutUnit> gridAreaPositionForInFlowGridItem(const RenderBox&, Style::GridTrackSizingDirection) const;
GridAxisPosition columnAxisPositionForGridItem(const RenderBox&) const;
GridAxisPosition rowAxisPositionForGridItem(const RenderBox&) const;
LayoutUnit columnAxisOffsetForGridItem(const RenderBox&) const;
LayoutUnit rowAxisOffsetForGridItem(const RenderBox&) const;
ContentAlignmentData computeContentPositionAndDistributionOffset(Style::GridTrackSizingDirection, const LayoutUnit& availableFreeSpace, unsigned numberOfGridTracks) const;
void setLogicalPositionForGridItem(RenderBox&) const;
LayoutUnit logicalOffsetForGridItem(const RenderBox&, Style::GridTrackSizingDirection) const;
LayoutUnit gridAreaBreadthForGridItemIncludingAlignmentOffsets(const RenderBox&, Style::GridTrackSizingDirection) const;
void paintChildren(PaintInfo& forSelf, const LayoutPoint& paintOffset, PaintInfo& forChild, bool usePrintRect) override;
bool hitTestChildren(const HitTestRequest&, HitTestResult&, const HitTestLocation&, const LayoutPoint& adjustedLocation, HitTestAction) override;
LayoutOptionalOutsets allowedLayoutOverflow() const override;
LayoutRect contentOverflowRect() const;
void applyStretchAlignmentToGridItemIfNeeded(RenderBox&, GridLayoutState&);
void applySubgridStretchAlignmentToGridItemIfNeeded(RenderBox&);
bool isChildEligibleForMarginTrim(Style::MarginTrimSide, const RenderBox&) const final;
std::optional<LayoutUnit> firstLineBaseline() const final;
std::optional<LayoutUnit> lastLineBaseline() const final;
const RenderBox* baselineGridItem(ItemPosition alignment) const;
LayoutUnit columnAxisBaselineOffsetForGridItem(const RenderBox&) const;
LayoutUnit rowAxisBaselineOffsetForGridItem(const RenderBox&) const;
unsigned nonCollapsedTracks(Style::GridTrackSizingDirection) const;
LayoutUnit translateRTLCoordinate(LayoutUnit) const;
bool shouldResetLogicalHeightBeforeLayout() const override { return true; }
bool aspectRatioPrefersInline(const RenderBox& gridItem, bool blockFlowIsColumnAxis);
Vector<RenderBox*> computeAspectRatioDependentAndBaselineItems(GridLayoutState&);
GridSpan gridSpanForOutOfFlowGridItem(const RenderBox&, Style::GridTrackSizingDirection) const;
bool computeGridPositionsForOutOfFlowGridItem(const RenderBox&, Style::GridTrackSizingDirection, int&, bool&, int&, bool&) const;
AutoRepeatType autoRepeatType(Style::GridTrackSizingDirection) const;
Vector<LayoutUnit>& positions(Style::GridTrackSizingDirection direction) { return direction == Style::GridTrackSizingDirection::Columns ? m_columnPositions : m_rowPositions; }
ContentAlignmentData& offsetBetweenTracks(Style::GridTrackSizingDirection direction) { return direction == Style::GridTrackSizingDirection::Columns ? m_offsetBetweenColumns : m_offsetBetweenRows; }
const ContentAlignmentData& offsetBetweenTracks(Style::GridTrackSizingDirection direction) const { return direction == Style::GridTrackSizingDirection::Columns ? m_offsetBetweenColumns : m_offsetBetweenRows; }
bool canCreateIntrinsicLogicalHeightsForRowSizingFirstPassCache() const;
class GridWrapper {
Grid m_layoutGrid;
public:
GridWrapper(RenderGrid&);
void resetCurrentGrid() const;
mutable std::reference_wrapper<Grid> m_currentGrid { std::ref(m_layoutGrid) };
} m_grid;
// FIXME: Refactor m_trackSizingAlgorithm to be inside of layoutGrid and layoutMasonry.
// https://bugs.webkit.org/show_bug.cgi?id=277496
GridTrackSizingAlgorithm m_trackSizingAlgorithm;
Vector<LayoutUnit> m_columnPositions;
Vector<LayoutUnit> m_rowPositions;
ContentAlignmentData m_offsetBetweenColumns;
ContentAlignmentData m_offsetBetweenRows;
mutable GridMasonryLayout m_masonryLayout;
bool m_baselineItemsCached {false};
mutable std::optional<GridItemSizeCache> m_intrinsicLogicalHeightsForRowSizingFirstPass;
bool layoutUsingGridFormattingContext();
std::optional<bool> m_hasGridFormattingContextLayout;
mutable bool m_isComputingTrackSizes { false };
};
} // namespace WebCore
SPECIALIZE_TYPE_TRAITS_RENDER_OBJECT(RenderGrid, isRenderGrid())