Commit 20a1c21e authored by Jacques Newman's avatar Jacques Newman Committed by Commit Bot

[GridNG] Auto placement for sparsely placed items.

This change brings the placement algorithm out of
NGGridLayoutAlgorithm and into NGGridAutoPlacement.
NGGridAutoPlacement exists only to encapsulate the
placement logic, and has a short lifetime on the stack.

NGGridAutoPlacement will resolve each GridItemData's
position and will ensure track coverage for that position.

Currently Auto Placement is implemented only for
sparsely packed grids.

Bug: 1045599
Change-Id: I5e1889ad5b4ea12cf3526736f71ffc512ae05bb3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2404110
Commit-Queue: Jacques Newman <janewman@microsoft.com>
Reviewed-by: default avatarKurt Catti-Schmidt <kschmi@microsoft.com>
Reviewed-by: default avatarIan Kilpatrick <ikilpatrick@chromium.org>
Reviewed-by: default avatarChristian Biesinger <cbiesinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#810793}
parent 2c667c7c
...@@ -341,6 +341,8 @@ blink_core_sources("layout") { ...@@ -341,6 +341,8 @@ blink_core_sources("layout") {
"ng/grid/ng_grid_child_iterator.h", "ng/grid/ng_grid_child_iterator.h",
"ng/grid/ng_grid_layout_algorithm.cc", "ng/grid/ng_grid_layout_algorithm.cc",
"ng/grid/ng_grid_layout_algorithm.h", "ng/grid/ng_grid_layout_algorithm.h",
"ng/grid/ng_grid_placement.cc",
"ng/grid/ng_grid_placement.h",
"ng/grid/ng_grid_track_collection.cc", "ng/grid/ng_grid_track_collection.cc",
"ng/grid/ng_grid_track_collection.h", "ng/grid/ng_grid_track_collection.h",
"ng/inline/empty_offset_mapping_builder.h", "ng/inline/empty_offset_mapping_builder.h",
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h" #include "third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h"
#include "third_party/blink/renderer/core/layout/ng/grid/ng_grid_child_iterator.h" #include "third_party/blink/renderer/core/layout/ng/grid/ng_grid_child_iterator.h"
#include "third_party/blink/renderer/core/layout/ng/grid/ng_grid_placement.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h" #include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h" #include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h" #include "third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h"
...@@ -34,6 +35,18 @@ scoped_refptr<const NGLayoutResult> NGGridLayoutAlgorithm::Layout() { ...@@ -34,6 +35,18 @@ scoped_refptr<const NGLayoutResult> NGGridLayoutAlgorithm::Layout() {
SetSpecifiedTracks(); SetSpecifiedTracks();
DetermineExplicitTrackStarts(); DetermineExplicitTrackStarts();
ConstructAndAppendGridItems(); ConstructAndAppendGridItems();
// TODO(janewman): Split placement into its own GridLayoutAlgorithmState
NGGridPlacement(
automatic_row_repetitions_, automatic_column_repetitions_,
explicit_row_start_, explicit_column_start_,
Style().IsGridAutoFlowAlgorithmSparse()
? NGGridPlacement::PackingBehavior::kSparse
: NGGridPlacement::PackingBehavior::kDense,
AutoFlowDirection(), Style(),
AutoFlowDirection() == kForRows ? column_count_ : row_count_,
block_row_track_collection_, block_column_track_collection_, items_)
.RunAutoPlacementAlgorithm();
block_column_track_collection_.FinalizeRanges(); block_column_track_collection_.FinalizeRanges();
block_row_track_collection_.FinalizeRanges(); block_row_track_collection_.FinalizeRanges();
...@@ -106,6 +119,24 @@ NGGridLayoutAlgorithm::RowTrackCollection() const { ...@@ -106,6 +119,24 @@ NGGridLayoutAlgorithm::RowTrackCollection() const {
NGGridLayoutAlgorithm::GridItemData::GridItemData(const NGBlockNode node) NGGridLayoutAlgorithm::GridItemData::GridItemData(const NGBlockNode node)
: node(node) {} : node(node) {}
NGGridLayoutAlgorithm::AutoPlacementType
NGGridLayoutAlgorithm::GridItemData::AutoPlacement(
GridTrackSizingDirection flow_direction) const {
bool is_major_indefinite = Span(flow_direction).IsIndefinite();
bool is_minor_indefinite =
Span(flow_direction == kForColumns ? kForRows : kForColumns)
.IsIndefinite();
if (is_minor_indefinite && is_major_indefinite)
return NGGridLayoutAlgorithm::AutoPlacementType::kBoth;
else if (is_minor_indefinite)
return NGGridLayoutAlgorithm::AutoPlacementType::kMinor;
else if (is_major_indefinite)
return NGGridLayoutAlgorithm::AutoPlacementType::kMajor;
return NGGridLayoutAlgorithm::AutoPlacementType::kNotNeeded;
}
wtf_size_t NGGridLayoutAlgorithm::GridItemData::StartLine( wtf_size_t NGGridLayoutAlgorithm::GridItemData::StartLine(
GridTrackSizingDirection track_direction) const { GridTrackSizingDirection track_direction) const {
const GridSpan& span = (track_direction == kForColumns) const GridSpan& span = (track_direction == kForColumns)
...@@ -124,6 +155,25 @@ wtf_size_t NGGridLayoutAlgorithm::GridItemData::EndLine( ...@@ -124,6 +155,25 @@ wtf_size_t NGGridLayoutAlgorithm::GridItemData::EndLine(
return span.EndLine(); return span.EndLine();
} }
const GridSpan& NGGridLayoutAlgorithm::GridItemData::Span(
GridTrackSizingDirection direction) const {
return (direction == kForColumns) ? resolved_position.columns
: resolved_position.rows;
}
void NGGridLayoutAlgorithm::GridItemData::SetSpan(
const GridSpan& span,
GridTrackSizingDirection track_direction) {
switch (track_direction) {
case kForColumns:
resolved_position.columns = span;
break;
case kForRows:
resolved_position.rows = span;
break;
}
}
NGGridLayoutAlgorithm::ReorderedGridItems::Iterator::Iterator( NGGridLayoutAlgorithm::ReorderedGridItems::Iterator::Iterator(
Vector<wtf_size_t>::const_iterator current_index, Vector<wtf_size_t>::const_iterator current_index,
Vector<GridItemData>* items) Vector<GridItemData>* items)
...@@ -177,8 +227,6 @@ void NGGridLayoutAlgorithm::ConstructAndAppendGridItems() { ...@@ -177,8 +227,6 @@ void NGGridLayoutAlgorithm::ConstructAndAppendGridItems() {
for (NGBlockNode child = iterator.NextChild(); child; for (NGBlockNode child = iterator.NextChild(); child;
child = iterator.NextChild()) { child = iterator.NextChild()) {
GridItemData grid_item = MeasureGridItem(child); GridItemData grid_item = MeasureGridItem(child);
EnsureTrackCoverageForGridItem(kForColumns, grid_item);
EnsureTrackCoverageForGridItem(kForRows, grid_item);
items_.emplace_back(grid_item); items_.emplace_back(grid_item);
} }
...@@ -261,34 +309,11 @@ void NGGridLayoutAlgorithm::SetSpecifiedTracks() { ...@@ -261,34 +309,11 @@ void NGGridLayoutAlgorithm::SetSpecifiedTracks() {
&grid_style.GridAutoRows().NGTrackList(), automatic_row_repetitions_); &grid_style.GridAutoRows().NGTrackList(), automatic_row_repetitions_);
} }
void NGGridLayoutAlgorithm::EnsureTrackCoverageForGridItem(
GridTrackSizingDirection track_direction,
GridItemData& grid_item) {
GridSpan span = GridPositionsResolver::ResolveGridPositionsFromStyle(
Style(), grid_item.node.Style(), track_direction,
AutoRepeatCountForDirection(track_direction));
// TODO(janewman): indefinite positions should be resolved with the auto
// placement algorithm.
if (span.IsIndefinite())
return;
if (track_direction == kForColumns) {
span.Translate(explicit_column_start_);
grid_item.resolved_position.columns = span;
block_column_track_collection_.EnsureTrackCoverage(span.StartLine(),
span.IntegerSpan());
} else {
span.Translate(explicit_row_start_);
grid_item.resolved_position.rows = span;
block_row_track_collection_.EnsureTrackCoverage(span.StartLine(),
span.IntegerSpan());
}
}
void NGGridLayoutAlgorithm::DetermineExplicitTrackStarts() { void NGGridLayoutAlgorithm::DetermineExplicitTrackStarts() {
DCHECK_EQ(0u, explicit_column_start_); DCHECK_EQ(0u, explicit_column_start_);
DCHECK_EQ(0u, explicit_row_start_); DCHECK_EQ(0u, explicit_row_start_);
DCHECK_EQ(0u, column_count_);
DCHECK_EQ(0u, row_count_);
NGGridChildIterator iterator(Node()); NGGridChildIterator iterator(Node());
for (NGBlockNode child = iterator.NextChild(); child; for (NGBlockNode child = iterator.NextChild(); child;
...@@ -302,10 +327,21 @@ void NGGridLayoutAlgorithm::DetermineExplicitTrackStarts() { ...@@ -302,10 +327,21 @@ void NGGridLayoutAlgorithm::DetermineExplicitTrackStarts() {
if (!column_span.IsIndefinite()) { if (!column_span.IsIndefinite()) {
explicit_column_start_ = std::max<int>( explicit_column_start_ = std::max<int>(
explicit_column_start_, -column_span.UntranslatedStartLine()); explicit_column_start_, -column_span.UntranslatedStartLine());
column_count_ =
std::max<int>(column_count_, column_span.UntranslatedEndLine());
} else {
column_count_ = std::max<int>(
column_count_, GridPositionsResolver::SpanSizeForAutoPlacedItem(
child.Style(), kForColumns));
} }
if (!row_span.IsIndefinite()) { if (!row_span.IsIndefinite()) {
explicit_row_start_ = explicit_row_start_ =
std::max<int>(explicit_row_start_, -row_span.UntranslatedStartLine()); std::max<int>(explicit_row_start_, -row_span.UntranslatedStartLine());
row_count_ = std::max<int>(row_count_, row_span.UntranslatedEndLine());
} else {
row_count_ = std::max<int>(
row_count_, GridPositionsResolver::SpanSizeForAutoPlacedItem(
child.Style(), kForRows));
} }
} }
} }
...@@ -435,6 +471,10 @@ wtf_size_t NGGridLayoutAlgorithm::AutoRepeatCountForDirection( ...@@ -435,6 +471,10 @@ wtf_size_t NGGridLayoutAlgorithm::AutoRepeatCountForDirection(
: automatic_row_repetitions_; : automatic_row_repetitions_;
} }
GridTrackSizingDirection NGGridLayoutAlgorithm::AutoFlowDirection() const {
return Style().IsGridAutoFlowDirectionRow() ? kForRows : kForColumns;
}
void NGGridLayoutAlgorithm::PlaceGridItems() { void NGGridLayoutAlgorithm::PlaceGridItems() {
NGGridChildIterator iterator(Node()); NGGridChildIterator iterator(Node());
LayoutUnit current_inline_offset, current_block_offset; LayoutUnit current_inline_offset, current_block_offset;
......
...@@ -19,6 +19,28 @@ class CORE_EXPORT NGGridLayoutAlgorithm ...@@ -19,6 +19,28 @@ class CORE_EXPORT NGGridLayoutAlgorithm
NGBoxFragmentBuilder, NGBoxFragmentBuilder,
NGBlockBreakToken> { NGBlockBreakToken> {
public: public:
enum class AutoPlacementType { kNotNeeded, kMajor, kMinor, kBoth };
struct GridItemData {
explicit GridItemData(const NGBlockNode node);
AutoPlacementType AutoPlacement(
GridTrackSizingDirection flow_direction) const;
wtf_size_t StartLine(GridTrackSizingDirection direction) const;
wtf_size_t EndLine(GridTrackSizingDirection direction) const;
const GridSpan& Span(GridTrackSizingDirection direction) const;
void SetSpan(const GridSpan& span, GridTrackSizingDirection direction);
const NGBlockNode node;
GridArea resolved_position;
NGBoxStrut margins;
LayoutUnit inline_size;
MinMaxSizes min_max_sizes;
bool is_spanning_flex_track : 1;
bool is_spanning_intrinsic_track : 1;
};
explicit NGGridLayoutAlgorithm(const NGLayoutAlgorithmParams& params); explicit NGGridLayoutAlgorithm(const NGLayoutAlgorithmParams& params);
scoped_refptr<const NGLayoutResult> Layout() override; scoped_refptr<const NGLayoutResult> Layout() override;
...@@ -39,23 +61,6 @@ class CORE_EXPORT NGGridLayoutAlgorithm ...@@ -39,23 +61,6 @@ class CORE_EXPORT NGGridLayoutAlgorithm
kCompletedLayout kCompletedLayout
}; };
struct GridItemData {
explicit GridItemData(const NGBlockNode node);
wtf_size_t StartLine(GridTrackSizingDirection track_direction) const;
wtf_size_t EndLine(GridTrackSizingDirection track_direction) const;
const NGBlockNode node;
GridArea resolved_position;
NGBoxStrut margins;
LayoutUnit inline_size;
MinMaxSizes min_max_sizes;
bool is_spanning_flex_track : 1;
bool is_spanning_intrinsic_track : 1;
};
class ReorderedGridItems { class ReorderedGridItems {
public: public:
class Iterator class Iterator
...@@ -116,6 +121,8 @@ class CORE_EXPORT NGGridLayoutAlgorithm ...@@ -116,6 +121,8 @@ class CORE_EXPORT NGGridLayoutAlgorithm
// Lays out and computes inline and block offsets for grid items. // Lays out and computes inline and block offsets for grid items.
void PlaceGridItems(); void PlaceGridItems();
GridTrackSizingDirection AutoFlowDirection() const;
GridLayoutAlgorithmState state_; GridLayoutAlgorithmState state_;
LogicalSize border_box_size_; LogicalSize border_box_size_;
LogicalSize child_percentage_size_; LogicalSize child_percentage_size_;
...@@ -131,6 +138,8 @@ class CORE_EXPORT NGGridLayoutAlgorithm ...@@ -131,6 +138,8 @@ class CORE_EXPORT NGGridLayoutAlgorithm
wtf_size_t explicit_column_start_ = 0; wtf_size_t explicit_column_start_ = 0;
wtf_size_t explicit_row_start_ = 0; wtf_size_t explicit_row_start_ = 0;
wtf_size_t column_count_ = 0;
wtf_size_t row_count_ = 0;
wtf_size_t automatic_column_repetitions_ = wtf_size_t automatic_column_repetitions_ =
NGGridBlockTrackCollection::kInvalidRangeIndex; NGGridBlockTrackCollection::kInvalidRangeIndex;
......
// 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_PLACEMENT_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_GRID_NG_GRID_PLACEMENT_H_
#include "third_party/blink/renderer/core/core_export.h"
#include "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/platform/wtf/vector.h"
namespace blink {
// This class encapsulates the Grid Item Placement Algorithm described by
// https://drafts.csswg.org/css-grid/#auto-placement-algo
class CORE_EXPORT NGGridPlacement {
STACK_ALLOCATED();
public:
enum class PackingBehavior { kSparse, kDense };
explicit NGGridPlacement(const wtf_size_t row_auto_repeat,
const wtf_size_t column_auto_repeat,
const wtf_size_t row_explicit_start,
const wtf_size_t column_explicit_start,
const PackingBehavior packing_behavior,
const GridTrackSizingDirection major_direction,
const ComputedStyle& grid_style,
wtf_size_t minor_max_end_line,
NGGridBlockTrackCollection& row_collection,
NGGridBlockTrackCollection& column_collection,
Vector<NGGridLayoutAlgorithm::GridItemData>& items);
void RunAutoPlacementAlgorithm();
private:
// Place non auto-positioned items and determine what items need auto
// placement, if any do, this returns true.
bool PlaceNonAutoGridItems();
// Place items that have a definite position on the major axis but need auto
// placement on the minor axis.
void PlaceGridItemsLockedToMajorAxis();
// Place item that has a definite position on the minor axis but need auto
// placement on the major axis.
void PlaceAutoMajorAxisGridItem(
NGGridLayoutAlgorithm::GridItemData& item_data);
// Place items that need automatic placement on both the major and minor axis.
void PlaceAutoBothAxisGridItem(
NGGridLayoutAlgorithm::GridItemData& item_data);
// Places a grid item if it has a definite position in the given direction,
// returns true if item was able to be positioned, false if item needs auto
// positioning in the given direction.
bool PlaceGridItem(
GridTrackSizingDirection grid_direction,
NGGridLayoutAlgorithm::NGGridLayoutAlgorithm::GridItemData& item_data);
void UpdatePlacementAndEnsureTrackCoverage(
GridSpan span,
GridTrackSizingDirection track_direction,
NGGridLayoutAlgorithm::NGGridLayoutAlgorithm::GridItemData& item_data);
// Returns true if the given placement would overlap with a placed item.
bool DoesItemOverlap(wtf_size_t major_start,
wtf_size_t major_end,
wtf_size_t minor_start,
wtf_size_t minor_end) const;
wtf_size_t AutoRepeat(GridTrackSizingDirection direction);
wtf_size_t ExplicitStart(GridTrackSizingDirection direction);
NGGridBlockTrackCollection& BlockCollection(
GridTrackSizingDirection direction);
const wtf_size_t row_auto_repeat_;
const wtf_size_t column_auto_repeat_;
const wtf_size_t row_explicit_start_;
const wtf_size_t column_explicit_start_;
const PackingBehavior packing_behavior_;
const GridTrackSizingDirection major_direction_;
const GridTrackSizingDirection minor_direction_;
// Used to resolve positions using GridPositionsResolver.
const ComputedStyle& grid_style_;
// Keeps track of the biggest minor end line among items with an explicit
// major line.
wtf_size_t minor_max_end_line_ = 0;
NGGridBlockTrackCollection& row_collection_;
NGGridBlockTrackCollection& column_collection_;
Vector<NGGridLayoutAlgorithm::GridItemData>& items_;
wtf_size_t starting_minor_line_ = 0;
wtf_size_t ending_minor_line_ = 0;
wtf_size_t placement_cursor_major;
wtf_size_t placement_cursor_minor;
// Subset of |items_| containing items that have a definite position on the
// major axis.
Vector<NGGridLayoutAlgorithm::GridItemData*> items_locked_to_major_axis_;
// Subset of |items_| containing items that do not have a definite position on
// the major axis.
Vector<NGGridLayoutAlgorithm::GridItemData*> items_not_locked_to_major_axis_;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_GRID_NG_GRID_PLACEMENT_H_
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