blob: 155c823f515b440be94041b595c3728b9bac0cc5 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_GRID_NG_GRID_LAYOUT_ALGORITHM_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_GRID_NG_GRID_LAYOUT_ALGORITHM_H_
#include "third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_algorithm.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
namespace blink {
class NGGridPlacement;
class CORE_EXPORT NGGridLayoutAlgorithm
: public NGLayoutAlgorithm<NGBlockNode,
NGBoxFragmentBuilder,
NGBlockBreakToken> {
public:
enum class AutoPlacementType { kNotNeeded, kMajor, kMinor, kBoth };
enum class AxisEdge { kStart, kCenter, kEnd, kBaseline };
enum class ItemType { kInGridFlow, kOutOfFlow };
// This enum corresponds to each step used to accommodate grid items across
// intrinsic tracks according to their min and max track sizing functions, as
// defined in https://drafts.csswg.org/css-grid-2/#algo-spanning-items.
enum class GridItemContributionType {
kForIntrinsicMinimums,
kForContentBasedMinimums,
kForMaxContentMinimums,
kForIntrinsicMaximums,
kForMaxContentMaximums,
kForFreeSpace
};
struct ItemSetIndices {
wtf_size_t begin = kNotFound;
wtf_size_t end = kNotFound;
};
struct CORE_EXPORT GridItemData {
explicit GridItemData(const NGBlockNode node) : node(node) {}
AutoPlacementType AutoPlacement(
GridTrackSizingDirection flow_direction) const;
const GridSpan& Span(GridTrackSizingDirection track_direction) const;
void SetSpan(const GridSpan& span,
GridTrackSizingDirection track_direction);
wtf_size_t StartLine(GridTrackSizingDirection track_direction) const;
wtf_size_t EndLine(GridTrackSizingDirection track_direction) const;
wtf_size_t SpanSize(GridTrackSizingDirection track_direction) const;
const TrackSpanProperties& GetTrackSpanProperties(
GridTrackSizingDirection track_direction) const;
void SetTrackSpanProperty(TrackSpanProperties::PropertyId property,
GridTrackSizingDirection track_direction);
bool IsSpanningFlexibleTrack(
GridTrackSizingDirection track_direction) const;
bool IsSpanningIntrinsicTrack(
GridTrackSizingDirection track_direction) const;
// For this item and track direction, computes and stores the pair of
// indices "begin" and "end" such that the item spans every set from the
// respective collection's |sets_| with an index in the range [begin, end).
// |grid_placement| is used to resolve the grid lines of out of flow items
// and it has a default nullptr value for grid items.
ItemSetIndices SetIndices(
const NGGridLayoutAlgorithmTrackCollection& track_collection,
const NGGridPlacement* grid_placement = nullptr);
const NGBlockNode node;
GridArea resolved_position;
NGBoxStrut margins;
AxisEdge inline_axis_alignment;
AxisEdge block_axis_alignment;
ItemType item_type;
bool is_inline_axis_stretched;
bool is_block_axis_stretched;
TrackSpanProperties column_span_properties;
TrackSpanProperties row_span_properties;
// These fields are used to determine the sets this item spans in the
// respective track collection; see |SetIndices|. We use optional since some
// scenarios don't require to compute the indices at all.
base::Optional<ItemSetIndices> column_set_indices;
base::Optional<ItemSetIndices> row_set_indices;
};
struct CORE_EXPORT GridItems {
class Iterator
: public std::iterator<std::input_iterator_tag, GridItemData> {
public:
Iterator(Vector<GridItemData>* item_data,
Vector<wtf_size_t>::const_iterator current_index)
: item_data_(item_data), current_index_(current_index) {
DCHECK(item_data_);
}
bool operator!=(const Iterator& other) const {
return current_index_ != other.current_index_ ||
item_data_ != other.item_data_;
}
Iterator& operator++() {
++current_index_;
return *this;
}
GridItemData* operator->() {
DCHECK(current_index_ && *current_index_ < item_data_->size());
return &(item_data_->at(*current_index_));
}
GridItemData& operator*() {
DCHECK(current_index_ && *current_index_ < item_data_->size());
return item_data_->at(*current_index_);
}
private:
Vector<GridItemData>* item_data_;
Vector<wtf_size_t>::const_iterator current_index_;
};
Iterator begin();
Iterator end();
void Append(const GridItemData& new_item_data);
bool IsEmpty() const;
// Grid items are appended to |item_data_| in the same order provided by
// |NGGridChildIterator|, which iterates over its children in order-modified
// document order; we want to keep such order since auto-placement and
// painting order rely on it later in the algorithm.
Vector<GridItemData> item_data;
Vector<wtf_size_t> reordered_item_indices;
};
// See |SetGeometry|.
struct SetOffsetData {
SetOffsetData(LayoutUnit offset, wtf_size_t last_indefinite_index)
: offset(offset), last_indefinite_index(last_indefinite_index) {}
LayoutUnit offset;
wtf_size_t last_indefinite_index;
};
// Represents the offsets for the sets, and the gutter-size.
//
// Initially we only know some of the set sizes - others will be indefinite.
// To represent this we store both the offset for the set, and the last index
// where there was an indefinite set (or kNotFound if everything so far has
// been definite). This allows us to get the appropriate size if a grid item
// spans only fixed tracks, but will allow us to return an indefinite size if
// it spans any indefinite set.
//
// As an example:
// grid-template-rows: auto auto 100px 100px auto 100px;
//
// Results in:
// | auto | auto | 100 | 100 | auto | 100 |
// [{0, kNotFound}, {0, 0}, {0, 1}, {100, 1}, {200, 1}, {200, 4}, {300, 4}]
//
// Various queries (start/end refer to the grid lines):
// start: 0, end: 1 -> indefinite as:
// "start <= sets[end].last_indefinite_index"
// start: 1, end: 3 -> indefinite as:
// "start <= sets[end].last_indefinite_index"
// start: 2, end: 4 -> 200px
// start: 5, end: 6 -> 100px
// start: 3, end: 5 -> indefinite as:
// "start <= sets[end].last_indefinite_index"
struct SetGeometry {
Vector<SetOffsetData> sets;
LayoutUnit gutter_size;
};
// Typically we pass around both the column, and row geometry together.
struct GridGeometry {
SetGeometry column_geometry;
SetGeometry row_geometry;
};
explicit NGGridLayoutAlgorithm(const NGLayoutAlgorithmParams& params);
scoped_refptr<const NGLayoutResult> Layout() override;
MinMaxSizesResult ComputeMinMaxSizes(const MinMaxSizesInput&) const override;
private:
friend class NGGridLayoutAlgorithmTest;
enum class SizingConstraint { kLayout, kMinContent, kMaxContent };
// Returns the size that a grid item will distribute across the tracks with an
// intrinsic sizing function it spans in the relevant track direction.
LayoutUnit ContributionSizeForGridItem(
const GridGeometry& grid_geometry,
const GridItemData& grid_item,
GridTrackSizingDirection track_direction,
GridItemContributionType contribution_type) const;
wtf_size_t ComputeAutomaticRepetitions(
GridTrackSizingDirection track_direction) const;
void ConstructAndAppendGridItems(
GridItems* grid_items,
Vector<GridItemData>* out_of_flow_items = nullptr) const;
GridItemData MeasureGridItem(const NGBlockNode node) const;
void BuildBlockTrackCollections(
GridItems* grid_items,
NGGridBlockTrackCollection* column_track_collection,
NGGridBlockTrackCollection* row_track_collection,
NGGridPlacement* grid_placement) const;
void BuildAlgorithmTrackCollections(
GridItems* grid_items,
NGGridLayoutAlgorithmTrackCollection* column_track_collection,
NGGridLayoutAlgorithmTrackCollection* row_track_collection,
NGGridPlacement* grid_placement) const;
// Ensure coverage in block collection after grid items have been placed.
void EnsureTrackCoverageForGridItems(
const GridItems& grid_items,
NGGridBlockTrackCollection* track_collection) const;
// For every grid item, caches properties of the track sizing functions it
// spans (i.e. whether an item spans intrinsic or flexible tracks).
void CacheGridItemsTrackSpanProperties(
const NGGridLayoutAlgorithmTrackCollection& track_collection,
GridItems* grid_items) const;
// Initializes the given track collection, and returns the base set geometry.
SetGeometry InitializeTrackSizes(
NGGridLayoutAlgorithmTrackCollection* track_collection) const;
// Calculates from the min and max track sizing functions the used track size.
void ComputeUsedTrackSizes(
SizingConstraint sizing_constraint,
const GridGeometry& grid_geometry,
NGGridLayoutAlgorithmTrackCollection* track_collection,
GridItems* grid_items) const;
// These methods implement the steps of the algorithm for intrinsic track size
// resolution defined in https://drafts.csswg.org/css-grid-2/#algo-content.
void ResolveIntrinsicTrackSizes(
const GridGeometry& grid_geometry,
NGGridLayoutAlgorithmTrackCollection* track_collection,
GridItems* grid_items) const;
void IncreaseTrackSizesToAccommodateGridItems(
const GridGeometry& grid_geometry,
GridItems::Iterator group_begin,
GridItems::Iterator group_end,
const bool is_group_spanning_flex_track,
GridItemContributionType contribution_type,
NGGridLayoutAlgorithmTrackCollection* track_collection) const;
void MaximizeTracks(
SizingConstraint sizing_constraint,
NGGridLayoutAlgorithmTrackCollection* track_collection) const;
void StretchAutoTracks(
SizingConstraint sizing_constraint,
NGGridLayoutAlgorithmTrackCollection* track_collection) const;
SetGeometry ComputeSetGeometry(
const NGGridLayoutAlgorithmTrackCollection& track_collection,
const LayoutUnit available_size) const;
// Gets the row or column gap of the grid.
LayoutUnit GridGap(GridTrackSizingDirection track_direction,
LayoutUnit available_size = kIndefiniteSize) const;
LayoutUnit DetermineFreeSpace(
SizingConstraint sizing_constraint,
const NGGridLayoutAlgorithmTrackCollection& track_collection) const;
const NGConstraintSpace CreateConstraintSpace(
const GridGeometry& grid_geometry,
const GridItemData& grid_item,
NGCacheSlot cache_slot,
LogicalRect* rect) const;
// Layout the |grid_items| based on the offsets provided.
void PlaceGridItems(const GridItems& grid_items,
const GridGeometry& grid_geometry,
LayoutUnit block_size);
// Computes the static position, grid area and its offset of out of flow
// elements in the grid.
void PlaceOutOfFlowItems(const Vector<GridItemData>& out_of_flow_items,
const GridGeometry& grid_geometry,
LayoutUnit block_size);
// Gets the out of flow descendants from the container builder and computes
// their containing block rect.
void PlaceOutOfFlowDescendants(
const NGGridLayoutAlgorithmTrackCollection& column_track_collection,
const NGGridLayoutAlgorithmTrackCollection& row_track_collection,
const GridGeometry& grid_geometry,
const NGGridPlacement& grid_placement,
LayoutUnit block_size);
// Helper method to compute the containing grid area for grid items or the
// containing block rect for out of flow elements.
LogicalRect ComputeContainingGridAreaRect(const GridGeometry& grid_geometry,
const GridItemData& item,
LayoutUnit block_size);
// Helper method that computes the offset and size of an item.
void ComputeOffsetAndSize(const GridItemData& item,
const SetGeometry& set_geometry,
const GridTrackSizingDirection track_direction,
LayoutUnit block_size,
LayoutUnit* start_offset,
LayoutUnit* size) const;
// Determines the position of the out of flow item's container.
void DeterminePositionOfOutOfFlowContainer(
Vector<GridItemData>* out_of_flow_items,
const GridTrackSizingDirection track_direction) const;
GridTrackSizingDirection AutoFlowDirection() const;
LogicalSize border_box_size_;
LogicalSize grid_available_size_;
LogicalSize grid_min_available_size_;
LogicalSize grid_max_available_size_;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_GRID_NG_GRID_LAYOUT_ALGORITHM_H_