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 const NamedGridLinesMap& gridLinesForSide(const RenderStyle& style, GridPositionSide side)
{
return isColumnSide(side) ? style.namedGridColumnLines() : style.namedGridRowLines();
}
static 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);
}
bool GridUnresolvedSpan::requiresAutoPlacement() const
{
return m_initialPosition.shouldBeResolvedAgainstOppositePosition() && m_finalPosition.shouldBeResolvedAgainstOppositePosition();
}
void GridUnresolvedSpan::adjustGridPositionsFromStyle(const RenderStyle& gridContainerStyle)
{
ASSERT(isColumnSide(m_initialPositionSide) == isColumnSide(m_finalPositionSide));
if (m_initialPosition.isSpan() && m_finalPosition.isSpan())
m_finalPosition.setAutoPosition();
if (m_initialPosition.isNamedGridArea() && isNonExistentNamedLineOrArea(m_initialPosition.namedGridLine(), gridContainerStyle, m_initialPositionSide))
m_initialPosition.setAutoPosition();
if (m_finalPosition.isNamedGridArea() && isNonExistentNamedLineOrArea(m_finalPosition.namedGridLine(), gridContainerStyle, m_finalPositionSide))
m_finalPosition.setAutoPosition();
if (m_initialPosition.isAuto() && m_finalPosition.isSpan() && !m_finalPosition.namedGridLine().isNull())
m_finalPosition.setSpanPosition(1, String());
if (m_finalPosition.isAuto() && m_initialPosition.isSpan() && !m_initialPosition.namedGridLine().isNull())
m_initialPosition.setSpanPosition(1, String());
}
unsigned GridResolvedPosition::explicitGridColumnCount(const RenderStyle& gridContainerStyle)
{
return std::min<unsigned>(gridContainerStyle.gridColumns().size(), kGridMaxTracks);
}
unsigned GridResolvedPosition::explicitGridRowCount(const RenderStyle& gridContainerStyle)
{
return std::min<unsigned>(gridContainerStyle.gridRows().size(), kGridMaxTracks);
}
static unsigned explicitGridSizeForSide(const RenderStyle& gridContainerStyle, GridPositionSide side)
{
return isColumnSide(side) ? GridResolvedPosition::explicitGridColumnCount(gridContainerStyle) : GridResolvedPosition::explicitGridRowCount(gridContainerStyle);
}
static GridResolvedPosition adjustGridPositionForRowEndColumnEndSide(unsigned resolvedPosition)
{
return resolvedPosition ? GridResolvedPosition(resolvedPosition - 1) : GridResolvedPosition(0);
}
static GridResolvedPosition adjustGridPositionForSide(unsigned resolvedPosition, GridPositionSide side)
{
if (side == ColumnEndSide || side == RowEndSide)
return adjustGridPositionForRowEndColumnEndSide(resolvedPosition);
return GridResolvedPosition(resolvedPosition);
}
static 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 unsigned lastLine = explicitGridSizeForSide(gridContainerStyle, side);
return adjustGridPositionForSide(lastLine, side);
}
unsigned namedGridLineIndex;
if (position.isPositive())
namedGridLineIndex = std::min<unsigned>(position.integerPosition(), it->value.size()) - 1;
else
namedGridLineIndex = std::max<int>(0, it->value.size() - abs(position.integerPosition()));
return adjustGridPositionForSide(it->value[namedGridLineIndex], side);
}
static inline unsigned firstNamedGridLineBeforePosition(unsigned position, const Vector<unsigned>& gridLines)
{
unsigned firstLineBeforePositionIndex = 0;
auto 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;
}
static GridSpan resolveRowStartColumnStartNamedGridLinePositionAgainstOppositePosition(const GridResolvedPosition& resolvedOppositePosition, const GridPosition& position, const Vector<unsigned>& gridLines)
{
unsigned gridLineIndex = std::max<int>(0, firstNamedGridLineBeforePosition(resolvedOppositePosition.toInt(), gridLines) - position.spanPosition() + 1);
GridResolvedPosition resolvedGridLinePosition = GridResolvedPosition(gridLines[gridLineIndex]);
return GridSpan(std::min<GridResolvedPosition>(resolvedGridLinePosition, resolvedOppositePosition), resolvedOppositePosition);
}
static GridSpan resolveRowEndColumnEndNamedGridLinePositionAgainstOppositePosition(const GridResolvedPosition& resolvedOppositePosition, const GridPosition& position, const Vector<unsigned>& gridLines)
{
ASSERT(gridLines.size());
unsigned firstLineAfterOppositePositionIndex = gridLines.size() - 1;
const unsigned* firstLineAfterOppositePosition = std::upper_bound(gridLines.begin(), gridLines.end(), resolvedOppositePosition);
if (firstLineAfterOppositePosition != gridLines.end())
firstLineAfterOppositePositionIndex = firstLineAfterOppositePosition - gridLines.begin();
unsigned gridLineIndex = std::min<unsigned>(gridLines.size() - 1, firstLineAfterOppositePositionIndex + position.spanPosition() - 1);
GridResolvedPosition resolvedGridLinePosition = adjustGridPositionForRowEndColumnEndSide(gridLines[gridLineIndex]);
if (resolvedGridLinePosition < resolvedOppositePosition)
resolvedGridLinePosition = resolvedOppositePosition;
return GridSpan(resolvedOppositePosition, resolvedGridLinePosition);
}
static GridSpan 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 GridSpan(resolvedOppositePosition, resolvedOppositePosition);
if (side == RowStartSide || side == ColumnStartSide)
return resolveRowStartColumnStartNamedGridLinePositionAgainstOppositePosition(resolvedOppositePosition, position, it->value);
return resolveRowEndColumnEndNamedGridLinePositionAgainstOppositePosition(resolvedOppositePosition, position, it->value);
}
static GridSpan resolveGridPositionAgainstOppositePosition(const RenderStyle& gridContainerStyle, const GridResolvedPosition& resolvedOppositePosition, const GridPosition& position, GridPositionSide side)
{
if (position.isAuto())
return GridSpan(resolvedOppositePosition, resolvedOppositePosition);
ASSERT(position.isSpan());
ASSERT(position.spanPosition() > 0);
if (!position.namedGridLine().isNull()) {
return resolveNamedGridLinePositionAgainstOppositePosition(gridContainerStyle, resolvedOppositePosition, position, side);
}
unsigned positionOffset = position.spanPosition() - 1;
if (isStartSide(side)) {
unsigned initialResolvedPosition = std::max<int>(0, resolvedOppositePosition.toInt() - positionOffset);
return GridSpan(initialResolvedPosition, resolvedOppositePosition);
}
return GridSpan(resolvedOppositePosition, resolvedOppositePosition.toInt() + positionOffset);
}
GridSpan GridResolvedPosition::resolveGridPositionsFromAutoPlacementPosition(const RenderStyle& gridContainerStyle, const RenderBox& gridItem, GridTrackSizingDirection direction, const GridResolvedPosition& resolvedInitialPosition)
{
GridUnresolvedSpan unresolvedSpan = unresolvedSpanFromStyle(gridContainerStyle, gridItem, direction);
ASSERT(unresolvedSpan.requiresAutoPlacement());
GridResolvedPosition resolvedFinalPosition = resolvedInitialPosition;
if (unresolvedSpan.initialPosition().isSpan())
return resolveGridPositionAgainstOppositePosition(gridContainerStyle, resolvedInitialPosition, unresolvedSpan.initialPosition(), unresolvedSpan.finalPositionSide());
if (unresolvedSpan.finalPosition().isSpan())
return resolveGridPositionAgainstOppositePosition(gridContainerStyle, resolvedInitialPosition, unresolvedSpan.finalPosition(), unresolvedSpan.finalPositionSide());
return GridSpan(resolvedInitialPosition, resolvedFinalPosition);
}
static 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 adjustGridPositionForSide(position.integerPosition() - 1, side);
unsigned resolvedPosition = abs(position.integerPosition()) - 1;
const unsigned endOfTrack = explicitGridSizeForSide(gridContainerStyle, side);
if (endOfTrack < resolvedPosition)
return 0;
return 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 adjustGridPositionForSide(implicitLine->value[0], side);
auto explicitLine = gridLineNames.find(namedGridLine);
if (explicitLine != gridLineNames.end())
return 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);
}
GridResolvedPosition::GridResolvedPosition(const GridPosition& position, GridPositionSide side)
{
ASSERT(position.integerPosition());
unsigned integerPosition = position.integerPosition() - 1;
m_integerPosition = adjustGridPositionForSide(integerPosition, side).m_integerPosition;
}
GridUnresolvedSpan GridResolvedPosition::unresolvedSpanFromStyle(const RenderStyle& gridContainerStyle, const RenderBox& gridItem, GridTrackSizingDirection direction)
{
GridPosition initialPosition = (direction == ForColumns) ? gridItem.style().gridItemColumnStart() : gridItem.style().gridItemRowStart();
auto initialPositionSide = (direction == ForColumns) ? ColumnStartSide : RowStartSide;
GridPosition finalPosition = (direction == ForColumns) ? gridItem.style().gridItemColumnEnd() : gridItem.style().gridItemRowEnd();
auto finalPositionSide = (direction == ForColumns) ? ColumnEndSide : RowEndSide;
GridUnresolvedSpan unresolvedSpan(initialPosition, initialPositionSide, finalPosition, finalPositionSide);
unresolvedSpan.adjustGridPositionsFromStyle(gridContainerStyle);
return unresolvedSpan;
}
GridSpan GridResolvedPosition::resolveGridPositionsFromStyle(const GridUnresolvedSpan& unresolvedSpan, const RenderStyle& gridContainerStyle)
{
ASSERT(!unresolvedSpan.requiresAutoPlacement());
if (unresolvedSpan.initialPosition().shouldBeResolvedAgainstOppositePosition()) {
auto finalResolvedPosition = resolveGridPositionFromStyle(gridContainerStyle, unresolvedSpan.finalPosition(), unresolvedSpan.finalPositionSide());
return resolveGridPositionAgainstOppositePosition(gridContainerStyle, finalResolvedPosition, unresolvedSpan.initialPosition(), unresolvedSpan.initialPositionSide());
}
if (unresolvedSpan.finalPosition().shouldBeResolvedAgainstOppositePosition()) {
auto initialResolvedPosition = resolveGridPositionFromStyle(gridContainerStyle, unresolvedSpan.initialPosition(), unresolvedSpan.initialPositionSide());
return resolveGridPositionAgainstOppositePosition(gridContainerStyle, initialResolvedPosition, unresolvedSpan.finalPosition(), unresolvedSpan.finalPositionSide());
}
GridResolvedPosition resolvedInitialPosition = resolveGridPositionFromStyle(gridContainerStyle, unresolvedSpan.initialPosition(), unresolvedSpan.initialPositionSide());
GridResolvedPosition resolvedFinalPosition = resolveGridPositionFromStyle(gridContainerStyle, unresolvedSpan.finalPosition(), unresolvedSpan.finalPositionSide());
return GridSpan(resolvedInitialPosition, std::max<GridResolvedPosition>(resolvedInitialPosition, resolvedFinalPosition));
}
}
#endif // ENABLE(CSS_GRID_LAYOUT)