GridResolvedPosition.cpp [plain text]
#include "config.h"
#include "GridResolvedPosition.h"
#if ENABLE(CSS_GRID_LAYOUT)
#include "GridCoordinate.h"
#include "RenderBox.h"
namespace WebCore {
static inline bool isColumnSide(GridPositionSide side)
{
return side == ColumnStartSide || side == ColumnEndSide;
}
static inline bool isStartSide(GridPositionSide side)
{
return side == ColumnStartSide || side == RowStartSide;
}
static size_t explicitGridSizeForSide(const RenderStyle& gridContainerStyle, GridPositionSide side)
{
return isColumnSide(side) ? gridContainerStyle.gridColumns().size() : gridContainerStyle.gridRows().size();
}
GridSpan GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(const RenderStyle& gridContainerStyle, const RenderBox& gridItem, GridTrackSizingDirection direction, const GridResolvedPosition& resolvedInitialPosition)
{
GridPosition initialPosition = (direction == ForColumns) ? gridItem.style().gridItemColumnStart() : gridItem.style().gridItemRowStart();
const GridPositionSide initialPositionSide = (direction == ForColumns) ? ColumnStartSide : RowStartSide;
GridPosition finalPosition = (direction == ForColumns) ? gridItem.style().gridItemColumnEnd() : gridItem.style().gridItemRowEnd();
const GridPositionSide finalPositionSide = (direction == ForColumns) ? ColumnEndSide : RowEndSide;
adjustGridPositionsFromStyle(gridContainerStyle, initialPosition, finalPosition, initialPositionSide, finalPositionSide);
ASSERT(initialPosition.shouldBeResolvedAgainstOppositePosition() && finalPosition.shouldBeResolvedAgainstOppositePosition());
GridResolvedPosition resolvedFinalPosition = resolvedInitialPosition;
if (initialPosition.isSpan())
resolvedFinalPosition = resolveGridPositionAgainstOppositePosition(gridContainerStyle, resolvedInitialPosition, initialPosition, finalPositionSide)->resolvedFinalPosition;
else if (finalPosition.isSpan())
resolvedFinalPosition = resolveGridPositionAgainstOppositePosition(gridContainerStyle, resolvedInitialPosition, finalPosition, finalPositionSide)->resolvedFinalPosition;
return GridSpan(resolvedInitialPosition, resolvedFinalPosition);
}
static inline const NamedGridLinesMap& gridLinesForSide(const RenderStyle& style, GridPositionSide side)
{
return isColumnSide(side) ? style.namedGridColumnLines() : style.namedGridRowLines();
}
static inline const String implicitNamedGridLineForSide(const String& lineName, GridPositionSide side)
{
return lineName + (isStartSide(side) ? "-start" : "-end");
}
static bool isNonExistentNamedLineOrArea(const String& lineName, const RenderStyle& style, GridPositionSide side)
{
const NamedGridLinesMap& gridLineNames = gridLinesForSide(style, side);
return !gridLineNames.contains(implicitNamedGridLineForSide(lineName, side)) && !gridLineNames.contains(lineName);
}
void GridResolvedPosition::adjustGridPositionsFromStyle(const RenderStyle& gridContainerStyle, GridPosition& initialPosition, GridPosition& finalPosition, GridPositionSide initialPositionSide, GridPositionSide finalPositionSide)
{
ASSERT(isColumnSide(initialPositionSide) == isColumnSide(finalPositionSide));
if (initialPosition.isSpan() && finalPosition.isSpan())
finalPosition.setAutoPosition();
if (initialPosition.isNamedGridArea() && isNonExistentNamedLineOrArea(initialPosition.namedGridLine(), gridContainerStyle, initialPositionSide))
initialPosition.setAutoPosition();
if (finalPosition.isNamedGridArea() && isNonExistentNamedLineOrArea(finalPosition.namedGridLine(), gridContainerStyle, finalPositionSide))
finalPosition.setAutoPosition();
if (initialPosition.isAuto() && finalPosition.isSpan() && !finalPosition.namedGridLine().isNull())
finalPosition.setSpanPosition(1, String());
if (finalPosition.isAuto() && initialPosition.isSpan() && !initialPosition.namedGridLine().isNull())
initialPosition.setSpanPosition(1, String());
}
std::unique_ptr<GridSpan> GridResolvedPosition::resolveGridPositionsFromStyle(const RenderStyle& gridContainerStyle, const RenderBox& gridItem, GridTrackSizingDirection direction)
{
GridPosition initialPosition = (direction == ForColumns) ? gridItem.style().gridItemColumnStart() : gridItem.style().gridItemRowStart();
const GridPositionSide initialPositionSide = (direction == ForColumns) ? ColumnStartSide : RowStartSide;
GridPosition finalPosition = (direction == ForColumns) ? gridItem.style().gridItemColumnEnd() : gridItem.style().gridItemRowEnd();
const GridPositionSide finalPositionSide = (direction == ForColumns) ? ColumnEndSide : RowEndSide;
adjustGridPositionsFromStyle(gridContainerStyle, initialPosition, finalPosition, initialPositionSide, finalPositionSide);
if (initialPosition.shouldBeResolvedAgainstOppositePosition() && finalPosition.shouldBeResolvedAgainstOppositePosition()) {
if (gridContainerStyle.isGridAutoFlowAlgorithmStack())
return std::make_unique<GridSpan>(0, 0);
return nullptr;
}
if (initialPosition.shouldBeResolvedAgainstOppositePosition()) {
const GridResolvedPosition finalResolvedPosition = resolveGridPositionFromStyle(gridContainerStyle, finalPosition, finalPositionSide);
return resolveGridPositionAgainstOppositePosition(gridContainerStyle, finalResolvedPosition, initialPosition, initialPositionSide);
}
if (finalPosition.shouldBeResolvedAgainstOppositePosition()) {
const GridResolvedPosition initialResolvedPosition = resolveGridPositionFromStyle(gridContainerStyle, initialPosition, initialPositionSide);
return resolveGridPositionAgainstOppositePosition(gridContainerStyle, initialResolvedPosition, finalPosition, finalPositionSide);
}
GridResolvedPosition resolvedInitialPosition = resolveGridPositionFromStyle(gridContainerStyle, initialPosition, initialPositionSide);
GridResolvedPosition resolvedFinalPosition = resolveGridPositionFromStyle(gridContainerStyle, finalPosition, finalPositionSide);
if (resolvedFinalPosition < resolvedInitialPosition)
resolvedFinalPosition = resolvedInitialPosition;
return std::make_unique<GridSpan>(resolvedInitialPosition, resolvedFinalPosition);
}
GridResolvedPosition GridResolvedPosition::resolveNamedGridLinePositionFromStyle(const RenderStyle& gridContainerStyle, const GridPosition& position, GridPositionSide side)
{
ASSERT(!position.namedGridLine().isNull());
const NamedGridLinesMap& gridLinesNames = isColumnSide(side) ? gridContainerStyle.namedGridColumnLines() : gridContainerStyle.namedGridRowLines();
NamedGridLinesMap::const_iterator it = gridLinesNames.find(position.namedGridLine());
if (it == gridLinesNames.end()) {
if (position.isPositive())
return 0;
const size_t lastLine = explicitGridSizeForSide(gridContainerStyle, side);
return GridResolvedPosition::adjustGridPositionForSide(lastLine, side);
}
size_t namedGridLineIndex;
if (position.isPositive())
namedGridLineIndex = std::min<size_t>(position.integerPosition(), it->value.size()) - 1;
else
namedGridLineIndex = std::max<int>(it->value.size() - abs(position.integerPosition()), 0);
return GridResolvedPosition::adjustGridPositionForSide(it->value[namedGridLineIndex], side);
}
GridResolvedPosition GridResolvedPosition::resolveGridPositionFromStyle(const RenderStyle& gridContainerStyle, const GridPosition& position, GridPositionSide side)
{
switch (position.type()) {
case ExplicitPosition: {
ASSERT(position.integerPosition());
if (!position.namedGridLine().isNull())
return resolveNamedGridLinePositionFromStyle(gridContainerStyle, position, side);
if (position.isPositive())
return GridResolvedPosition::adjustGridPositionForSide(position.integerPosition() - 1, side);
size_t resolvedPosition = abs(position.integerPosition()) - 1;
const size_t endOfTrack = explicitGridSizeForSide(gridContainerStyle, side);
if (endOfTrack < resolvedPosition)
return 0;
return GridResolvedPosition::adjustGridPositionForSide(endOfTrack - resolvedPosition, side);
}
case NamedGridAreaPosition:
{
String namedGridLine = position.namedGridLine();
ASSERT(!isNonExistentNamedLineOrArea(namedGridLine, gridContainerStyle, side));
const NamedGridLinesMap& gridLineNames = gridLinesForSide(gridContainerStyle, side);
auto implicitLine = gridLineNames.find(implicitNamedGridLineForSide(namedGridLine, side));
if (implicitLine != gridLineNames.end())
return GridResolvedPosition::adjustGridPositionForSide(implicitLine->value[0], side);
auto explicitLine = gridLineNames.find(namedGridLine);
if (explicitLine != gridLineNames.end())
return GridResolvedPosition::adjustGridPositionForSide(explicitLine->value[0], side);
ASSERT_NOT_REACHED();
return 0;
}
case AutoPosition:
case SpanPosition:
ASSERT_NOT_REACHED();
return GridResolvedPosition(0);
}
ASSERT_NOT_REACHED();
return GridResolvedPosition(0);
}
std::unique_ptr<GridSpan> GridResolvedPosition::resolveGridPositionAgainstOppositePosition(const RenderStyle& gridContainerStyle, const GridResolvedPosition& resolvedOppositePosition, const GridPosition& position, GridPositionSide side)
{
if (position.isAuto())
return std::make_unique<GridSpan>(resolvedOppositePosition, resolvedOppositePosition);
ASSERT(position.isSpan());
ASSERT(position.spanPosition() > 0);
if (!position.namedGridLine().isNull()) {
return resolveNamedGridLinePositionAgainstOppositePosition(gridContainerStyle, resolvedOppositePosition, position, side);
}
size_t positionOffset = position.spanPosition() - 1;
if (isStartSide(side)) {
size_t initialResolvedPosition = std::max<int>(0, resolvedOppositePosition.toInt() - positionOffset);
return std::make_unique<GridSpan>(initialResolvedPosition, resolvedOppositePosition);
}
return std::make_unique<GridSpan>(resolvedOppositePosition, resolvedOppositePosition.toInt() + positionOffset);
}
std::unique_ptr<GridSpan> GridResolvedPosition::resolveNamedGridLinePositionAgainstOppositePosition(const RenderStyle& gridContainerStyle, const GridResolvedPosition& resolvedOppositePosition, const GridPosition& position, GridPositionSide side)
{
ASSERT(position.isSpan());
ASSERT(!position.namedGridLine().isNull());
ASSERT(position.spanPosition() > 0);
const NamedGridLinesMap& gridLinesNames = isColumnSide(side) ? gridContainerStyle.namedGridColumnLines() : gridContainerStyle.namedGridRowLines();
NamedGridLinesMap::const_iterator it = gridLinesNames.find(position.namedGridLine());
if (it == gridLinesNames.end())
return std::make_unique<GridSpan>(resolvedOppositePosition, resolvedOppositePosition);
if (side == RowStartSide || side == ColumnStartSide)
return resolveRowStartColumnStartNamedGridLinePositionAgainstOppositePosition(resolvedOppositePosition, position, it->value);
return resolveRowEndColumnEndNamedGridLinePositionAgainstOppositePosition(resolvedOppositePosition, position, it->value);
}
static inline size_t firstNamedGridLineBeforePosition(size_t position, const Vector<size_t>& gridLines)
{
size_t firstLineBeforePositionIndex = 0;
const size_t* firstLineBeforePosition = std::lower_bound(gridLines.begin(), gridLines.end(), position);
if (firstLineBeforePosition != gridLines.end()) {
if (*firstLineBeforePosition > position && firstLineBeforePosition != gridLines.begin())
--firstLineBeforePosition;
firstLineBeforePositionIndex = firstLineBeforePosition - gridLines.begin();
}
return firstLineBeforePositionIndex;
}
std::unique_ptr<GridSpan> GridResolvedPosition::resolveRowStartColumnStartNamedGridLinePositionAgainstOppositePosition(const GridResolvedPosition& resolvedOppositePosition, const GridPosition& position, const Vector<size_t>& gridLines)
{
size_t gridLineIndex = std::max<int>(0, firstNamedGridLineBeforePosition(resolvedOppositePosition.toInt(), gridLines) - position.spanPosition() + 1);
GridResolvedPosition resolvedGridLinePosition = GridResolvedPosition(gridLines[gridLineIndex]);
if (resolvedGridLinePosition > resolvedOppositePosition)
resolvedGridLinePosition = resolvedOppositePosition;
return std::make_unique<GridSpan>(resolvedGridLinePosition, resolvedOppositePosition);
}
std::unique_ptr<GridSpan> GridResolvedPosition::resolveRowEndColumnEndNamedGridLinePositionAgainstOppositePosition(const GridResolvedPosition& resolvedOppositePosition, const GridPosition& position, const Vector<size_t>& gridLines)
{
size_t firstLineAfterOppositePositionIndex = gridLines.size() - 1;
const size_t* firstLineAfterOppositePosition = std::upper_bound(gridLines.begin(), gridLines.end(), resolvedOppositePosition);
if (firstLineAfterOppositePosition != gridLines.end())
firstLineAfterOppositePositionIndex = firstLineAfterOppositePosition - gridLines.begin();
size_t gridLineIndex = std::min(gridLines.size() - 1, firstLineAfterOppositePositionIndex + position.spanPosition() - 1);
GridResolvedPosition resolvedGridLinePosition = GridResolvedPosition::adjustGridPositionForRowEndColumnEndSide(gridLines[gridLineIndex]);
if (resolvedGridLinePosition < resolvedOppositePosition)
resolvedGridLinePosition = resolvedOppositePosition;
return std::make_unique<GridSpan>(resolvedOppositePosition, resolvedGridLinePosition);
}
}
#endif // ENABLE(CSS_GRID_LAYOUT)