Commit 032a699c authored by Sergio Villar Senin's avatar Sergio Villar Senin Committed by Commit Bot

[css-grid] Refactor Grid to allow different implementations

The current Grid data structure is mostly generic but it still
depends on a grid representation based on Vectors of Vectors. In
order to allow future memory efficient representations we should
remove that dependency. This CL moves all the vector dependent
code to a new class named VectorGrid.

Apart from that, GridIterator was moved to Grid and also
refectored as we would need to provide different implementations
of the iterator depending on the data structure used for grids.

Last but not least, in order to limit the amount of changes in
the clients of these two interfaces, a couple of factory methods
were added to create both Grid and GridIterator objects. These
Create() methods are the ones instantiating the specific
Grid (and GridIterator) representations.

R=jfernandez@igalia.com, rego@igalia.com

Change-Id: I59d9f8df93c3c65390a0f22aaf8064359f9248f4
Reviewed-on: https://chromium-review.googlesource.com/1075331
Commit-Queue: Sergio Villar <svillar@igalia.com>
Reviewed-by: default avatarJavier Fernandez <jfernandez@igalia.com>
Reviewed-by: default avatarManuel Rego Casasnovas <rego@igalia.com>
Cr-Commit-Position: refs/heads/master@{#564857}
parent 3b37c4e4
......@@ -12,41 +12,56 @@
namespace blink {
std::unique_ptr<Grid> Grid::Create(const LayoutGrid* layout_grid) {
return base::WrapUnique(new VectorGrid(layout_grid));
}
Grid::Grid(const LayoutGrid* grid) : order_iterator_(grid) {}
size_t Grid::NumTracks(GridTrackSizingDirection direction) const {
VectorGrid::VectorGrid(const LayoutGrid* grid) : Grid(grid) {}
size_t VectorGrid::NumTracks(GridTrackSizingDirection direction) const {
if (direction == kForRows)
return grid_.size();
return grid_.size() ? grid_[0].size() : 0;
return matrix_.size();
return matrix_.size() ? matrix_[0].size() : 0;
}
void Grid::EnsureGridSize(size_t maximum_row_size, size_t maximum_column_size) {
void VectorGrid::EnsureGridSize(size_t maximum_row_size,
size_t maximum_column_size) {
const size_t old_row_size = NumTracks(kForRows);
if (maximum_row_size > old_row_size) {
grid_.Grow(maximum_row_size);
matrix_.Grow(maximum_row_size);
for (size_t row = old_row_size; row < NumTracks(kForRows); ++row)
grid_[row].Grow(NumTracks(kForColumns));
matrix_[row].Grow(NumTracks(kForColumns));
}
if (maximum_column_size > NumTracks(kForColumns)) {
for (size_t row = 0; row < NumTracks(kForRows); ++row)
grid_[row].Grow(maximum_column_size);
matrix_[row].Grow(maximum_column_size);
}
}
void Grid::insert(LayoutBox& child, const GridArea& area) {
void VectorGrid::insert(LayoutBox& child, const GridArea& area) {
DCHECK(area.rows.IsTranslatedDefinite());
DCHECK(area.columns.IsTranslatedDefinite());
EnsureGridSize(area.rows.EndLine(), area.columns.EndLine());
for (const auto& row : area.rows) {
for (const auto& column : area.columns)
grid_[row][column].push_back(&child);
matrix_[row][column].push_back(&child);
}
SetGridItemArea(child, area);
}
std::unique_ptr<Grid::GridIterator> VectorGrid::CreateIterator(
GridTrackSizingDirection direction,
size_t fixed_track_index,
size_t varying_track_index) const {
return base::WrapUnique(new VectorGridIterator(
*this, direction, fixed_track_index, varying_track_index));
}
void Grid::SetSmallestTracksStart(int row_start, int column_start) {
smallest_row_start_ = row_start;
smallest_column_start_ = column_start;
......@@ -73,10 +88,6 @@ void Grid::SetGridItemPaintOrder(const LayoutBox& item, size_t order) {
grid_items_indexes_map_.Set(&item, order);
}
const GridCell& Grid::Cell(size_t row, size_t column) const {
return grid_[row][column];
}
#if DCHECK_IS_ON()
bool Grid::HasAnyGridItemPaintOrder() const {
return !grid_items_indexes_map_.IsEmpty();
......@@ -139,11 +150,11 @@ void Grid::SetNeedsItemsPlacement(bool needs_items_placement) {
needs_items_placement_ = needs_items_placement;
if (!needs_items_placement) {
grid_.ShrinkToFit();
ConsolidateGridDataStructure();
return;
}
grid_.resize(0);
ClearGridDataStructure();
grid_item_area_.clear();
grid_items_indexes_map_.clear();
has_any_orthogonal_grid_item_ = false;
......@@ -155,34 +166,39 @@ void Grid::SetNeedsItemsPlacement(bool needs_items_placement) {
auto_repeat_empty_rows_ = nullptr;
}
GridIterator::GridIterator(const Grid& grid,
GridTrackSizingDirection direction,
size_t fixed_track_index,
size_t varying_track_index)
: grid_(grid.grid_),
direction_(direction),
Grid::GridIterator::GridIterator(GridTrackSizingDirection direction,
size_t fixed_track_index,
size_t varying_track_index)
: direction_(direction),
row_index_((direction == kForColumns) ? varying_track_index
: fixed_track_index),
column_index_((direction == kForColumns) ? fixed_track_index
: varying_track_index),
child_index_(0) {
DCHECK(!grid_.IsEmpty());
DCHECK(!grid_[0].IsEmpty());
DCHECK_LT(row_index_, grid_.size());
DCHECK_LT(column_index_, grid_[0].size());
child_index_(0) {}
VectorGridIterator::VectorGridIterator(const VectorGrid& grid,
GridTrackSizingDirection direction,
size_t fixed_track_index,
size_t varying_track_index)
: GridIterator(direction, fixed_track_index, varying_track_index),
matrix_(grid.matrix_) {
DCHECK(!matrix_.IsEmpty());
DCHECK(!matrix_[0].IsEmpty());
DCHECK_LT(row_index_, matrix_.size());
DCHECK_LT(column_index_, matrix_[0].size());
}
LayoutBox* GridIterator::NextGridItem() {
DCHECK(!grid_.IsEmpty());
DCHECK(!grid_[0].IsEmpty());
LayoutBox* VectorGridIterator::NextGridItem() {
DCHECK(!matrix_.IsEmpty());
DCHECK(!matrix_[0].IsEmpty());
size_t& varying_track_index =
(direction_ == kForColumns) ? row_index_ : column_index_;
const size_t end_of_varying_track_index =
(direction_ == kForColumns) ? grid_.size() : grid_[0].size();
(direction_ == kForColumns) ? matrix_.size() : matrix_[0].size();
for (; varying_track_index < end_of_varying_track_index;
++varying_track_index) {
const GridCell& children = grid_[row_index_][column_index_];
const GridCell& children = matrix_[row_index_][column_index_];
if (child_index_ < children.size())
return children[child_index_++];
......@@ -191,19 +207,20 @@ LayoutBox* GridIterator::NextGridItem() {
return nullptr;
}
bool GridIterator::CheckEmptyCells(size_t row_span, size_t column_span) const {
DCHECK(!grid_.IsEmpty());
DCHECK(!grid_[0].IsEmpty());
bool VectorGridIterator::CheckEmptyCells(size_t row_span,
size_t column_span) const {
DCHECK(!matrix_.IsEmpty());
DCHECK(!matrix_[0].IsEmpty());
// Ignore cells outside current grid as we will grow it later if needed.
size_t max_rows = std::min(row_index_ + row_span, grid_.size());
size_t max_columns = std::min(column_index_ + column_span, grid_[0].size());
size_t max_rows = std::min(row_index_ + row_span, matrix_.size());
size_t max_columns = std::min(column_index_ + column_span, matrix_[0].size());
// This adds a O(N^2) behavior that shouldn't be a big deal as we expect
// spanning areas to be small.
for (size_t row = row_index_; row < max_rows; ++row) {
for (size_t column = column_index_; column < max_columns; ++column) {
const GridCell& children = grid_[row][column];
const GridCell& children = matrix_[row][column];
if (!children.IsEmpty())
return false;
}
......@@ -212,11 +229,11 @@ bool GridIterator::CheckEmptyCells(size_t row_span, size_t column_span) const {
return true;
}
std::unique_ptr<GridArea> GridIterator::NextEmptyGridArea(
std::unique_ptr<GridArea> VectorGridIterator::NextEmptyGridArea(
size_t fixed_track_span,
size_t varying_track_span) {
DCHECK(!grid_.IsEmpty());
DCHECK(!grid_[0].IsEmpty());
DCHECK(!matrix_.IsEmpty());
DCHECK(!matrix_[0].IsEmpty());
DCHECK_GE(fixed_track_span, 1u);
DCHECK_GE(varying_track_span, 1u);
......@@ -228,7 +245,7 @@ std::unique_ptr<GridArea> GridIterator::NextEmptyGridArea(
size_t& varying_track_index =
(direction_ == kForColumns) ? row_index_ : column_index_;
const size_t end_of_varying_track_index =
(direction_ == kForColumns) ? grid_.size() : grid_[0].size();
(direction_ == kForColumns) ? matrix_.size() : matrix_[0].size();
for (; varying_track_index < end_of_varying_track_index;
++varying_track_index) {
if (CheckEmptyCells(row_span, column_span)) {
......
......@@ -29,14 +29,19 @@ class GridIterator;
// LayoutGrid object to place the grid items on a grid like structure, so that
// they could be accessed by rows/columns instead of just traversing the DOM or
// Layout trees.
class Grid final {
class Grid {
public:
Grid(const LayoutGrid*);
static std::unique_ptr<Grid> Create(const LayoutGrid*);
virtual size_t NumTracks(GridTrackSizingDirection) const = 0;
virtual void EnsureGridSize(size_t maximum_row_size,
size_t maximum_column_size) = 0;
virtual void insert(LayoutBox&, const GridArea&) = 0;
size_t NumTracks(GridTrackSizingDirection) const;
virtual const GridCell& Cell(size_t row, size_t column) const = 0;
void EnsureGridSize(size_t maximum_row_size, size_t maximum_column_size);
void insert(LayoutBox&, const GridArea&);
virtual ~Grid(){};
// Note that out of flow children are not grid items.
bool HasGridItems() const { return !grid_item_area_.IsEmpty(); }
......@@ -54,8 +59,6 @@ class Grid final {
size_t GridItemPaintOrder(const LayoutBox&) const;
void SetGridItemPaintOrder(const LayoutBox&, size_t order);
const GridCell& Cell(size_t row, size_t column) const;
int SmallestTrackStart(GridTrackSizingDirection) const;
void SetSmallestTracksStart(int row_start, int column_start);
......@@ -81,6 +84,42 @@ class Grid final {
bool HasAnyGridItemPaintOrder() const;
#endif
class GridIterator {
public:
virtual LayoutBox* NextGridItem() = 0;
virtual std::unique_ptr<GridArea> NextEmptyGridArea(
size_t fixed_track_span,
size_t varying_track_span) = 0;
virtual ~GridIterator() = default;
protected:
// |direction| is the direction that is fixed to |fixed_track_index| so e.g
// GridIterator(grid_, kForColumns, 1) will walk over the rows of the 2nd
// column.
GridIterator(GridTrackSizingDirection,
size_t fixed_track_index,
size_t varying_track_index);
GridTrackSizingDirection direction_;
size_t row_index_;
size_t column_index_;
size_t child_index_;
DISALLOW_COPY_AND_ASSIGN(GridIterator);
};
virtual std::unique_ptr<GridIterator> CreateIterator(
GridTrackSizingDirection,
size_t fixed_track_index,
size_t varying_track_index = 0) const = 0;
protected:
Grid(const LayoutGrid*);
virtual void ClearGridDataStructure() = 0;
virtual void ConsolidateGridDataStructure() = 0;
private:
friend class GridIterator;
......@@ -95,8 +134,6 @@ class Grid final {
bool has_any_orthogonal_grid_item_{false};
bool needs_items_placement_{true};
GridAsMatrix grid_;
HashMap<const LayoutBox*, GridArea> grid_item_area_;
HashMap<const LayoutBox*, size_t> grid_items_indexes_map_;
......@@ -104,32 +141,50 @@ class Grid final {
std::unique_ptr<OrderedTrackIndexSet> auto_repeat_empty_rows_{nullptr};
};
// TODO(svillar): ideally the Grid class should be the one returning an iterator
// for its contents.
class GridIterator final {
class VectorGrid final : public Grid {
public:
// |direction| is the direction that is fixed to |fixedTrackIndex| so e.g
// GridIterator(m_grid, ForColumns, 1) will walk over the rows of the 2nd
// column.
GridIterator(const Grid&,
GridTrackSizingDirection,
size_t fixed_track_index,
size_t varying_track_index = 0);
explicit VectorGrid(const LayoutGrid*);
LayoutBox* NextGridItem();
size_t NumTracks(GridTrackSizingDirection) const override;
const GridCell& Cell(size_t row, size_t column) const override {
return matrix_[row][column];
}
void insert(LayoutBox&, const GridArea&) override;
bool CheckEmptyCells(size_t row_span, size_t column_span) const;
private:
friend class VectorGridIterator;
void EnsureGridSize(size_t maximum_row_size,
size_t maximum_column_size) override;
void ClearGridDataStructure() override { matrix_.resize(0); };
void ConsolidateGridDataStructure() override { matrix_.ShrinkToFit(); }
std::unique_ptr<GridIterator> CreateIterator(
GridTrackSizingDirection,
size_t fixed_track_index,
size_t varying_track_index = 0) const override;
GridAsMatrix matrix_;
};
class VectorGridIterator final : public Grid::GridIterator {
public:
VectorGridIterator(const VectorGrid&,
GridTrackSizingDirection,
size_t fixed_track_span,
size_t varying_track_span = 0);
std::unique_ptr<GridArea> NextEmptyGridArea(size_t fixed_track_span,
size_t varying_track_span);
LayoutBox* NextGridItem() override;
std::unique_ptr<GridArea> NextEmptyGridArea(
size_t fixed_track_span,
size_t varying_track_span) override;
private:
const GridAsMatrix& grid_;
GridTrackSizingDirection direction_;
size_t row_index_;
size_t column_index_;
size_t child_index_;
DISALLOW_COPY_AND_ASSIGN(GridIterator);
bool CheckEmptyCells(size_t row_span, size_t column_span) const;
const GridAsMatrix& matrix_;
DISALLOW_COPY_AND_ASSIGN(VectorGridIterator);
};
} // namespace blink
......
......@@ -524,8 +524,9 @@ double IndefiniteSizeStrategy::FindUsedFlexFraction(
return flex_fraction;
for (size_t i = 0; i < flexible_sized_tracks_index.size(); ++i) {
GridIterator iterator(grid, direction, flexible_sized_tracks_index[i]);
while (LayoutBox* grid_item = iterator.NextGridItem()) {
auto iterator =
grid.CreateIterator(direction, flexible_sized_tracks_index[i]);
while (LayoutBox* grid_item = iterator->NextGridItem()) {
const GridSpan& span = grid.GridItemSpan(*grid_item, direction);
// Do not include already processed items.
......@@ -1226,9 +1227,9 @@ void GridTrackSizingAlgorithm::ResolveIntrinsicTrackSizes() {
if (grid_.HasGridItems()) {
HashSet<LayoutBox*> items_set;
for (const auto& track_index : content_sized_tracks_index_) {
GridIterator iterator(grid_, direction_, track_index);
auto iterator = grid_.CreateIterator(direction_, track_index);
GridTrack& track = Tracks(direction_)[track_index];
while (LayoutBox* grid_item = iterator.NextGridItem()) {
while (auto* grid_item = iterator->NextGridItem()) {
if (items_set.insert(grid_item).is_new_entry) {
const GridSpan& span = grid_.GridItemSpan(*grid_item, direction_);
if (span.IntegerSpan() == 1) {
......
......@@ -57,32 +57,32 @@ class LayoutGrid final : public LayoutBlock {
Vector<LayoutUnit> TrackSizesForComputedStyle(GridTrackSizingDirection) const;
const Vector<LayoutUnit>& ColumnPositions() const {
DCHECK(!grid_.NeedsItemsPlacement());
DCHECK(!grid_->NeedsItemsPlacement());
return column_positions_;
}
const Vector<LayoutUnit>& RowPositions() const {
DCHECK(!grid_.NeedsItemsPlacement());
DCHECK(!grid_->NeedsItemsPlacement());
return row_positions_;
}
const GridCell& GetGridCell(int row, int column) const {
SECURITY_DCHECK(!grid_.NeedsItemsPlacement());
return grid_.Cell(row, column);
SECURITY_DCHECK(!grid_->NeedsItemsPlacement());
return grid_->Cell(row, column);
}
const Vector<LayoutBox*>& ItemsOverflowingGridArea() const {
SECURITY_DCHECK(!grid_.NeedsItemsPlacement());
SECURITY_DCHECK(!grid_->NeedsItemsPlacement());
return grid_items_overflowing_grid_area_;
}
int PaintIndexForGridItem(const LayoutBox* layout_box) const {
SECURITY_DCHECK(!grid_.NeedsItemsPlacement());
return grid_.GridItemPaintOrder(*layout_box);
SECURITY_DCHECK(!grid_->NeedsItemsPlacement());
return grid_->GridItemPaintOrder(*layout_box);
}
size_t AutoRepeatCountForDirection(GridTrackSizingDirection direction) const {
return grid_.AutoRepeatTracks(direction);
return grid_->AutoRepeatTracks(direction);
}
LayoutUnit TranslateOutOfFlowRTLCoordinate(const LayoutBox&,
......@@ -310,7 +310,7 @@ class LayoutGrid final : public LayoutBlock {
LineDirectionMode);
static const StyleContentAlignmentData& ContentAlignmentNormalBehavior();
Grid grid_;
std::unique_ptr<Grid> grid_;
GridTrackSizingAlgorithm track_sizing_algorithm_;
Vector<LayoutUnit> row_positions_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment