diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_data.h b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_data.h index 473220dac3ba9..c0af4027c2cfc 100644 --- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_data.h +++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_data.h @@ -8,6 +8,7 @@ #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/layout/ng/grid/ng_grid_line_resolver.h" #include "third_party/blink/renderer/core/layout/ng/grid/ng_grid_track_collection.h" +#include "third_party/blink/renderer/platform/wtf/ref_counted.h" #include "third_party/blink/renderer/platform/wtf/vector.h" namespace blink { @@ -132,10 +133,14 @@ class CORE_EXPORT NGGridLayoutData { return AreEqual(columns_, other.columns_) && AreEqual(rows_, other.rows_); } + bool operator!=(const NGGridLayoutData& other) const { + return !(*this == other); + } + bool HasSubgriddedAxis(GridTrackSizingDirection track_direction) const { - return !((track_direction == kForColumns) - ? columns_ && columns_->IsForSizing() - : rows_ && rows_->IsForSizing()); + return (track_direction == kForColumns) + ? !(columns_ && columns_->IsForSizing()) + : !(rows_ && rows_->IsForSizing()); } NGGridLayoutTrackCollection& Columns() const { @@ -156,10 +161,6 @@ class CORE_EXPORT NGGridLayoutData { (track_direction == kForColumns) ? Columns() : Rows()); } - // TODO(ethavar): This two should disappear in the upcoming patch. - const NGGridLayoutTrackCollection* columns() const { return columns_.get(); } - const NGGridLayoutTrackCollection* rows() const { return rows_.get(); } - void SetTrackCollection( std::unique_ptr track_collection) { DCHECK(track_collection); @@ -176,6 +177,191 @@ class CORE_EXPORT NGGridLayoutData { std::unique_ptr rows_; }; +// Subgrid layout relies on the root grid to perform the track sizing algorithm +// for every level of nested subgrids. This class is a collection of finalized +// layout data of every grid/subgrid in the entire grid tree, which will be +// passed down to the constraint space of a subgrid to perform layout. +// +// The tree is represented by two vectors satisfying the following conditions: +// - The nodes in the tree are indexed using preorder traversal. +// - Each subtree is guaranteed to be contained in a single contiguous range. +// - We can iterate over a node's children by skipping over their subtrees; +// i.e., the first child of a node `k` is always at position `k+1`, the next +// sibling comes `subtree_size_[k+1]` positions later, and so on. +// +// (0) +// / \ +// (1) (7) +// / \ / \ +// (2) (5) (8) (9) +// / \ \ +// (3) (4) (6) (0) +// (1) (7) +// (2) (5) (8)(9) +// (3)(4) (6) +// subtree_size_ = [10, 6, 3, 1, 1, 2, 1, 3, 1, 1] +// +// Note that this class allows subtrees to be compared for equality; this is +// important because when we store this tree within a constraint space we want +// to be able to invalidate the cached layout result of a subgrid based on +// whether the provided subtree's track were sized exactly the same. +class NGGridLayoutTree : public RefCounted { + public: + explicit NGGridLayoutTree(wtf_size_t size = 1) { + subtree_size_.ReserveInitialCapacity(size); + layout_data_.ReserveInitialCapacity(size); + } + + bool AreSubtreesEqual(wtf_size_t subtree_root, + const NGGridLayoutTree& other, + wtf_size_t other_subtree_root) const { + DCHECK_LT(other_subtree_root, other.subtree_size_.size()); + DCHECK_LT(subtree_root, subtree_size_.size()); + + const wtf_size_t subtree_size = subtree_size_[subtree_root]; + if (subtree_size != other.subtree_size_[other_subtree_root]) { + return false; + } + + DCHECK_LE(other_subtree_root + subtree_size, other.layout_data_.size()); + DCHECK_LE(subtree_root + subtree_size, layout_data_.size()); + + for (wtf_size_t i = 0; i < subtree_size; ++i) { + if (other.layout_data_[other_subtree_root + i] != + layout_data_[subtree_root + i]) { + return false; + } + } + return true; + } + + const NGGridLayoutData& LayoutData(wtf_size_t index) const { + DCHECK_LT(index, layout_data_.size()); + return layout_data_[index]; + } + + wtf_size_t Size() const { + DCHECK_EQ(layout_data_.size(), subtree_size_.size()); + return layout_data_.size(); + } + + wtf_size_t SubtreeSize(wtf_size_t index) const { + DCHECK_LT(index, subtree_size_.size()); + return subtree_size_[index]; + } + + void Append(const NGGridLayoutData& layout_data, wtf_size_t subtree_size) { + subtree_size_.emplace_back(subtree_size); + layout_data_.emplace_back(layout_data); + } + + private: + // Holds the finalized layout data of each grid in the tree. + Vector layout_data_; + + // The size of the subtree rooted at each grid node. For a given index `k`, + // this means that the range [k, k + subtree_size_[k]) in both vectors + // represent the data of the subtree rooted at grid node `k`. + Vector subtree_size_; +}; + +// This class represents a subtree in a `NGGridLayoutTree` and mostly serves two +// purposes: provide seamless iteration over the tree structure and compare +// input subtrees to invalidate a subgrid's cached layout result. +// +// A subtree is represented by a pointer to the original layout tree's data (see +// `NGGridLayoutTree` description) and the index of the subtree's root. However, +// in order to iterate over the siblings of a given subtree we need to store the +// index of the next sibling of its parent, aka the parent's end index, so that +// the iterator doesn't traverse outside of the parent's subtree, e.g.: +// +// (0) +// (1) (7) +// (2) (5) (8)(9) +// (3)(4) (6) +// layout_tree_.subtree_size_ = [10, 6, 3, 1, 1, 2, 1, 3, 1, 1] +// +// We can compute the next sibling of a subtree rooted at index 2 by adding the +// subtree size at that index (2 + 3 = 5). On the other hand, when we want to +// compute the next sibling for the subtree at index 5, adding the subtree size +// (5 + 2) it's equal to its parent's next sibling (aka parent's end index), so +// we can determine that such subtree doesn't have a next sibling. + +class NGGridLayoutSubtree { + DISALLOW_NEW(); + + public: + NGGridLayoutSubtree() = default; + + explicit NGGridLayoutSubtree( + scoped_refptr&& layout_tree) + : layout_tree_(std::move(layout_tree)), subtree_root_(0) { + DCHECK(layout_tree_); + parent_end_index_ = layout_tree_->Size(); + } + + NGGridLayoutSubtree(const scoped_refptr& layout_tree, + wtf_size_t parent_end_index, + wtf_size_t subtree_root) { + DCHECK(layout_tree); + DCHECK_LE(parent_end_index, layout_tree->Size()); + DCHECK_LE(subtree_root, parent_end_index); + + // If the subtree root is beyond the parent's end index, we will keep this + // instance as a null subtree to indicate the end iterator for siblings. + if (subtree_root < parent_end_index) { + layout_tree_ = layout_tree; + parent_end_index_ = parent_end_index; + subtree_root_ = subtree_root; + } + } + + explicit operator bool() const { return static_cast(layout_tree_); } + + // This method is meant to be used for layout invalidation, so we only care + // about comparing the layout data of both subtrees. + bool operator==(const NGGridLayoutSubtree& other) const { + return (layout_tree_ && other.layout_tree_) + ? layout_tree_->AreSubtreesEqual( + subtree_root_, *other.layout_tree_, other.subtree_root_) + : !layout_tree_ && !other.layout_tree_; + } + + // First child is always at `subtree_root_ + 1` (see `NGGridLayoutTree`). + NGGridLayoutSubtree FirstChild() const { + return NGGridLayoutSubtree(layout_tree_, + /* parent_end_index */ NextSiblingIndex(), + /* subtree_root */ subtree_root_ + 1); + } + + NGGridLayoutSubtree NextSibling() const { + return NGGridLayoutSubtree(layout_tree_, + /* parent_end_index */ parent_end_index_, + /* subtree_root */ NextSiblingIndex()); + } + + const NGGridLayoutData& LayoutData() const { + DCHECK(layout_tree_); + return layout_tree_->LayoutData(subtree_root_); + } + + private: + wtf_size_t NextSiblingIndex() const { + DCHECK(layout_tree_); + return subtree_root_ + layout_tree_->SubtreeSize(subtree_root_); + } + + // Pointer to the layout tree data shared by multiple subtree instances. + scoped_refptr layout_tree_; + + // Index of the next sibling of this subtree's parent; used to avoid iterating + // outside of the parent's subtree when computing this subtree's next sibling. + wtf_size_t parent_end_index_{kNotFound}; + + // Index of this subtree's root node. + wtf_size_t subtree_root_{kNotFound}; +}; + } // namespace blink #endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_GRID_NG_GRID_DATA_H_ diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.h b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.h index 7ee52e39558b7..5ac9fd2186bf8 100644 --- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.h +++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.h @@ -335,6 +335,4 @@ class CORE_EXPORT GridItems { } // namespace blink -WTF_ALLOW_CLEAR_UNUSED_SLOTS_WITH_MEM_FUNCTIONS(blink::GridItemData) - #endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_GRID_NG_GRID_ITEM_H_ diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc index a9db37e9d7d22..640c8638f4d0a 100644 --- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc @@ -229,8 +229,6 @@ const NGLayoutResult* NGGridLayoutAlgorithm::Layout() { const NGLayoutResult* NGGridLayoutAlgorithm::LayoutInternal() { PaintLayerScrollableArea::DelayScrollOffsetClampScope delay_clamp_scope; - - const auto& node = Node(); HeapVector> oof_children; // Don't re-accumulate out-of-flow children if we're resuming layout, since @@ -268,9 +266,21 @@ const NGLayoutResult* NGGridLayoutAlgorithm::LayoutInternal() { ComputeGridGeometry(&grid_sizing_tree, &intrinsic_block_size); } - // Subgridded items must be placed by their parent. + // Subgridded items must be laid out by their parent. + // + // TODO(ethavar): Removing subgridded items seems weird since there are more + // parts in the code where we explicitly want to ignore them. We need to allow + // the caller to decide whether they want to iterate over subgridded items. grid_items.RemoveSubgriddedItems(); + const auto& constraint_space = ConstraintSpace(); + const auto* cached_layout_subtree = constraint_space.GridLayoutSubtree(); + + const auto layout_subtree = + cached_layout_subtree + ? *cached_layout_subtree + : NGGridLayoutSubtree(grid_sizing_tree.FinalizeTree()); + Vector row_break_between; LayoutUnit consumed_grid_block_size; Vector grid_items_placement_data; @@ -290,7 +300,7 @@ const NGLayoutResult* NGGridLayoutAlgorithm::LayoutInternal() { } else { row_offset_adjustments = Vector(layout_data.Rows().GetSetCount() + 1); - PlaceGridItems(grid_items, layout_data, &row_break_between, + PlaceGridItems(grid_items, layout_subtree, &row_break_between, &grid_items_placement_data); } @@ -299,11 +309,12 @@ const NGLayoutResult* NGGridLayoutAlgorithm::LayoutInternal() { &row_offset_adjustments, &intrinsic_block_size, &consumed_grid_block_size); } else { - PlaceGridItems(grid_items, layout_data, &row_break_between); + PlaceGridItems(grid_items, layout_subtree, &row_break_between); } + const auto& node = Node(); const auto& border_padding = BorderPadding(); - const auto& constraint_space = ConstraintSpace(); + const auto block_size = ComputeBlockSizeForFragment( constraint_space, Style(), border_padding, intrinsic_block_size, container_builder_.InlineSize()); @@ -610,68 +621,16 @@ NGGridSizingTree NGGridLayoutAlgorithm::BuildGridSizingTree( HeapVector>* oof_children) const { NGGridSizingTree sizing_tree; - const auto& constraint_space = ConstraintSpace(); - const auto* subgridded_columns = constraint_space.SubgriddedColumns(); - const auto* subgridded_rows = constraint_space.SubgriddedRows(); - - // For subgrids, we build only the direct children and rely on the subgridded - // tracks from the constraint space to build layout data. This isn't ideal for - // the grid sizing tree approach, but we do it to keep passing subgrid tests. - // - // TODO(ethavar): Remove all of this redundant code. - if (subgridded_columns || subgridded_rows) { + if (const auto* layout_subtree = ConstraintSpace().GridLayoutSubtree()) { const auto& node = Node(); - const auto& container_style = Style(); auto& sizing_data = sizing_tree.CreateSizingData(); - bool has_nested_subgrid; - sizing_data.grid_items = node.ConstructGridItems( - node.CachedPlacementData(), oof_children, &has_nested_subgrid); - if (has_nested_subgrid) - node.AppendSubgriddedItems(&sizing_data.grid_items); - - auto BuildSizingCollection = [&](GridTrackSizingDirection track_direction) { - NGGridRangeBuilder range_builder( - container_style, node.CachedPlacementData(), track_direction); - - bool must_create_baselines = false; - for (auto& grid_item : sizing_data.grid_items) { - must_create_baselines |= - grid_item.IsBaselineSpecifiedForDirection(track_direction); - - auto& range_indices = grid_item.RangeIndices(track_direction); - range_builder.EnsureTrackCoverage(grid_item.StartLine(track_direction), - grid_item.SpanSize(track_direction), - &range_indices.begin, - &range_indices.end); - } - sizing_data.layout_data.SetTrackCollection( - std::make_unique( - range_builder.FinalizeRanges(), must_create_baselines, - track_direction)); - }; - - if (subgridded_columns) { - sizing_data.layout_data.SetTrackCollection( - std::make_unique( - *subgridded_columns, BorderScrollbarPadding(), - ComputeMarginsForSelf(constraint_space, container_style))); - } else { - BuildSizingCollection(kForColumns); - } - - if (subgridded_rows) { - sizing_data.layout_data.SetTrackCollection( - std::make_unique( - *subgridded_rows, BorderScrollbarPadding(), - ComputeMarginsForSelf(constraint_space, container_style))); - } else { - BuildSizingCollection(kForRows); - } - return sizing_tree; + sizing_data.grid_items = + node.ConstructGridItems(node.CachedPlacementData(), oof_children); + sizing_data.layout_data = layout_subtree->LayoutData(); + } else { + BuildGridSizingSubtree(&sizing_tree, oof_children); } - - BuildGridSizingSubtree(&sizing_tree, oof_children); return sizing_tree; } @@ -1032,6 +991,12 @@ LayoutUnit NGGridLayoutAlgorithm::ContributionSizeForGridItem( GridItemData* grid_item) const { DCHECK(grid_item); + // TODO(ethavar): Measuring a subgrid depends on a new method that computes a + // single axis track collection, this is incorrect in the meantime. + if (grid_item->IsSubgrid()) { + return LayoutUnit(); + } + // From https://drafts.csswg.org/css-grid-2/#subgrid-size-contribution: // The subgrid itself [...] acts as if it was completely empty for track // sizing purposes in the subgridded dimension. @@ -2861,8 +2826,9 @@ NGConstraintSpace NGGridLayoutAlgorithm::CreateConstraintSpace( const NGGridLayoutData& layout_data, const LogicalSize& containing_grid_area_size, absl::optional opt_fixed_block_size, - absl::optional opt_fragment_relative_block_offset, - bool min_block_size_should_encompass_intrinsic_size) const { + NGGridLayoutSubtree&& layout_subtree, + bool min_block_size_should_encompass_intrinsic_size, + absl::optional opt_fragment_relative_block_offset) const { const auto& container_constraint_space = ConstraintSpace(); NGConstraintSpaceBuilder builder( @@ -2881,48 +2847,21 @@ NGConstraintSpace NGGridLayoutAlgorithm::CreateConstraintSpace( } if (grid_item.IsSubgrid()) { - if (containing_grid_area_size.inline_size != kIndefiniteSize) + if (layout_subtree) { + builder.SetGridLayoutSubtree(std::move(layout_subtree)); + } + if (containing_grid_area_size.inline_size != kIndefiniteSize) { builder.SetIsFixedInlineSize(true); - if (containing_grid_area_size.block_size != kIndefiniteSize) + } + if (containing_grid_area_size.block_size != kIndefiniteSize) { builder.SetIsFixedBlockSize(true); + } } builder.SetPercentageResolutionSize(containing_grid_area_size); builder.SetInlineAutoBehavior(grid_item.inline_auto_behavior); builder.SetBlockAutoBehavior(grid_item.block_auto_behavior); - // TODO(ethavar): Currently, we inherit a subgridded track collection, but our - // new approach to subgrid layout requires to pass the grid sizing subtree. - if (layout_data.columns() && layout_data.rows() && - grid_item.has_subgridded_columns) { - const auto& range_indices = grid_item.is_parallel_with_root_grid - ? grid_item.column_range_indices - : grid_item.row_range_indices; - - const auto& track_collection = grid_item.is_parallel_with_root_grid - ? layout_data.Columns() - : layout_data.Rows(); - - builder.SetSubgriddedColumns(std::make_unique( - track_collection.CreateSubgridCollection( - range_indices.begin, range_indices.end, kForColumns))); - } - - if (layout_data.columns() && layout_data.rows() && - grid_item.has_subgridded_rows) { - const auto& range_indices = grid_item.is_parallel_with_root_grid - ? grid_item.row_range_indices - : grid_item.column_range_indices; - - const auto& track_collection = grid_item.is_parallel_with_root_grid - ? layout_data.Rows() - : layout_data.Columns(); - - builder.SetSubgriddedRows(std::make_unique( - track_collection.CreateSubgridCollection(range_indices.begin, - range_indices.end, kForRows))); - } - if (container_constraint_space.HasBlockFragmentation() && opt_fragment_relative_block_offset) { if (min_block_size_should_encompass_intrinsic_size) @@ -2940,8 +2879,11 @@ NGConstraintSpace NGGridLayoutAlgorithm::CreateConstraintSpaceForLayout( const GridItemData& grid_item, const NGGridLayoutData& layout_data, LogicalRect* containing_grid_area, - absl::optional opt_fragment_relative_block_offset, - bool min_block_size_should_encompass_intrinsic_size) const { + NGGridLayoutSubtree&& layout_subtree, + bool min_block_size_should_encompass_intrinsic_size, + absl::optional opt_fragment_relative_block_offset) const { + DCHECK(containing_grid_area); + ComputeGridItemOffsetAndSize(grid_item, layout_data.Columns(), &containing_grid_area->offset.inline_offset, &containing_grid_area->size.inline_size); @@ -2950,11 +2892,11 @@ NGConstraintSpace NGGridLayoutAlgorithm::CreateConstraintSpaceForLayout( &containing_grid_area->offset.block_offset, &containing_grid_area->size.block_size); - return CreateConstraintSpace(NGCacheSlot::kLayout, grid_item, layout_data, - containing_grid_area->size, - /* opt_fixed_block_size */ absl::nullopt, - opt_fragment_relative_block_offset, - min_block_size_should_encompass_intrinsic_size); + return CreateConstraintSpace( + NGCacheSlot::kLayout, grid_item, layout_data, containing_grid_area->size, + /* opt_fixed_block_size */ absl::nullopt, std::move(layout_subtree), + min_block_size_should_encompass_intrinsic_size, + opt_fragment_relative_block_offset); } NGConstraintSpace NGGridLayoutAlgorithm::CreateConstraintSpaceForMeasure( @@ -2975,7 +2917,8 @@ NGConstraintSpace NGGridLayoutAlgorithm::CreateConstraintSpaceForMeasure( &containing_grid_area_size.inline_size); } return CreateConstraintSpace(NGCacheSlot::kMeasure, grid_item, layout_data, - containing_grid_area_size, opt_fixed_block_size); + containing_grid_area_size, opt_fixed_block_size, + /* layout_subtree */ NGGridLayoutSubtree()); } NGGridLayoutAlgorithm NGGridLayoutAlgorithm::CreateSubgridLayoutAlgorithm( @@ -3136,15 +3079,17 @@ class BaselineAccumulator { void NGGridLayoutAlgorithm::PlaceGridItems( const GridItems& grid_items, - const NGGridLayoutData& layout_data, + const NGGridLayoutSubtree& layout_subtree, Vector* out_row_break_between, Vector* out_grid_items_placement_data) { DCHECK(out_row_break_between); const auto& container_space = ConstraintSpace(); + const auto& layout_data = layout_subtree.LayoutData(); + const auto container_writing_direction = container_space.GetWritingDirection(); - bool should_propagate_child_break_values = + const bool should_propagate_child_break_values = container_space.ShouldPropagateChildBreakValues(); if (should_propagate_child_break_values) { @@ -3153,11 +3098,21 @@ void NGGridLayoutAlgorithm::PlaceGridItems( } BaselineAccumulator baseline_accumulator(Style().GetFontBaseline()); + auto next_subgrid_subtree = layout_subtree.FirstChild(); for (const auto& grid_item : grid_items) { + NGGridLayoutSubtree child_layout_subtree; + + if (grid_item.IsSubgrid()) { + DCHECK(next_subgrid_subtree); + child_layout_subtree = next_subgrid_subtree; + next_subgrid_subtree = next_subgrid_subtree.NextSibling(); + } + LogicalRect containing_grid_area; - const auto space = CreateConstraintSpaceForLayout(grid_item, layout_data, - &containing_grid_area); + const auto space = CreateConstraintSpaceForLayout( + grid_item, layout_data, &containing_grid_area, + std::move(child_layout_subtree)); const auto& item_style = grid_item.node.Style(); const auto margins = ComputeMarginsFor(space, item_style, container_space); @@ -3405,8 +3360,9 @@ void NGGridLayoutAlgorithm::PlaceGridItemsForFragmentation( .has_descendant_that_depends_on_percentage_block_size); LogicalRect grid_area; const auto space = CreateConstraintSpaceForLayout( - grid_item, *layout_data, &grid_area, fragment_relative_block_offset, - min_block_size_should_encompass_intrinsic_size); + grid_item, *layout_data, &grid_area, NGGridLayoutSubtree(), + min_block_size_should_encompass_intrinsic_size, + fragment_relative_block_offset); // Make the grid area relative to this fragment. const auto item_row_set_index = grid_item.SetIndices(kForRows).begin; diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h index c2fdcd6da5c0e..a71f04426a2c9 100644 --- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h +++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h @@ -185,17 +185,19 @@ class CORE_EXPORT NGGridLayoutAlgorithm const NGGridLayoutData& layout_data, const LogicalSize& containing_grid_area_size, absl::optional opt_fixed_block_size, + NGGridLayoutSubtree&& layout_subtree, + bool min_block_size_should_encompass_intrinsic_size = false, absl::optional opt_fragment_relative_block_offset = - absl::nullopt, - bool min_block_size_should_encompass_intrinsic_size = false) const; + absl::nullopt) const; NGConstraintSpace CreateConstraintSpaceForLayout( const GridItemData& grid_item, const NGGridLayoutData& layout_data, LogicalRect* containing_grid_area, + NGGridLayoutSubtree&& layout_subtree = NGGridLayoutSubtree(), + bool min_block_size_should_encompass_intrinsic_size = false, absl::optional opt_fragment_relative_block_offset = - absl::nullopt, - bool min_block_size_should_encompass_intrinsic_size = false) const; + absl::nullopt) const; NGConstraintSpace CreateConstraintSpaceForMeasure( const GridItemData& grid_item, @@ -218,7 +220,7 @@ class CORE_EXPORT NGGridLayoutAlgorithm // of each item before fragmentation occurs. void PlaceGridItems( const GridItems& grid_items, - const NGGridLayoutData& layout_data, + const NGGridLayoutSubtree& layout_subtree, Vector* out_row_break_between, Vector* out_grid_items_placement_data = nullptr); diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_node.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_node.cc index d854bdb0d6ffa..3b47013f193c1 100644 --- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_node.cc +++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_node.cc @@ -17,8 +17,6 @@ GridItems NGGridNode::ConstructGridItems( const NGGridPlacementData& placement_data, HeapVector>* oof_children, bool* has_nested_subgrid) const { - DCHECK(has_nested_subgrid); - return ConstructGridItems(placement_data, Style(), placement_data.HasStandaloneAxis(kForColumns), placement_data.HasStandaloneAxis(kForRows), diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_node.h b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_node.h index 10b14b74c6015..6755132c60f17 100644 --- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_node.h +++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_node.h @@ -24,7 +24,7 @@ class CORE_EXPORT NGGridNode final : public NGBlockNode { // If |oof_children| is provided, aggregate any out of flow children. GridItems ConstructGridItems(const NGGridPlacementData& placement_data, HeapVector>* oof_children, - bool* has_nested_subgrid) const; + bool* has_nested_subgrid = nullptr) const; void AppendSubgriddedItems(GridItems* grid_items) const; diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_sizing_tree.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_sizing_tree.cc index e7348e89f0675..39b3d03d0c715 100644 --- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_sizing_tree.cc +++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_sizing_tree.cc @@ -28,21 +28,13 @@ NGSubgriddedItemData::CreateSubgridCollection( range_indices.begin, range_indices.end, track_direction)); } -NGGridSizingTree NGGridSizingTree::CopySubtree(wtf_size_t subtree_root) const { - DCHECK_LT(subtree_root, sizing_data_.size()); - - const wtf_size_t subtree_size = sizing_data_[subtree_root]->subtree_size; - DCHECK_LE(subtree_root + subtree_size, sizing_data_.size()); - - NGGridSizingTree subtree_copy(subtree_size); - for (wtf_size_t i = 0; i < subtree_size; ++i) { - auto& copy_data = subtree_copy.CreateSizingData(); - const auto& original_data = *sizing_data_[subtree_root + i]; - - copy_data.subtree_size = original_data.subtree_size; - copy_data.layout_data = original_data.layout_data; +scoped_refptr NGGridSizingTree::FinalizeTree() const { + auto layout_tree = + base::MakeRefCounted(sizing_data_.size()); + for (const auto& sizing_data : sizing_data_) { + layout_tree->Append(sizing_data.layout_data, sizing_data.subtree_size); } - return subtree_copy; + return layout_tree; } } // namespace blink diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_sizing_tree.h b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_sizing_tree.h index efe4e3415320e..94fc1bb677f25 100644 --- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_sizing_tree.h +++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_sizing_tree.h @@ -12,7 +12,7 @@ namespace blink { struct NGGridSizingData { - USING_FAST_MALLOC(NGGridSizingData); + DISALLOW_NEW(); public: GridItems grid_items; @@ -65,38 +65,35 @@ class CORE_EXPORT NGGridSizingTree { DISALLOW_NEW(); public: - using GridSizingDataVector = Vector, 16>; - + NGGridSizingTree() = default; NGGridSizingTree(NGGridSizingTree&&) = default; NGGridSizingTree(const NGGridSizingTree&) = delete; NGGridSizingTree& operator=(NGGridSizingTree&&) = default; NGGridSizingTree& operator=(const NGGridSizingTree&) = delete; - explicit NGGridSizingTree(wtf_size_t tree_size = 1) { - sizing_data_.ReserveInitialCapacity(tree_size); - } - - NGGridSizingData& CreateSizingData() { - return *sizing_data_.emplace_back(std::make_unique()); - } + NGGridSizingData& CreateSizingData() { return sizing_data_.emplace_back(); } NGGridSizingData& At(wtf_size_t index) { DCHECK_LT(index, sizing_data_.size()); - return *sizing_data_[index]; + return sizing_data_[index]; } NGGridSizingData& operator[](wtf_size_t index) { return At(index); } wtf_size_t SubtreeSize(wtf_size_t index) const { DCHECK_LT(index, sizing_data_.size()); - return sizing_data_[index]->subtree_size; + return sizing_data_[index].subtree_size; } - NGGridSizingTree CopySubtree(wtf_size_t subtree_root) const; + // Creates a copy of the current grid geometry for the entire tree in a new + // `NGGridLayoutTree` instance, which doesn't hold the grid items and its + // stored in a `scoped_refptr` to be shared by multiple subtrees. + scoped_refptr FinalizeTree() const; + wtf_size_t Size() const { return sizing_data_.size(); } private: - GridSizingDataVector sizing_data_; + Vector sizing_data_; }; } // namespace blink diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h index 9b3ed7f9e5c69..5d85c521f6335 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h +++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h @@ -749,12 +749,8 @@ class CORE_EXPORT NGConstraintSpace final { return HasRareData() ? rare_data_->LinesUntilClamp() : absl::nullopt; } - const NGGridLayoutTrackCollection* SubgriddedColumns() const { - return HasRareData() ? rare_data_->SubgriddedColumns() : nullptr; - } - - const NGGridLayoutTrackCollection* SubgriddedRows() const { - return HasRareData() ? rare_data_->SubgriddedRows() : nullptr; + const NGGridLayoutSubtree* GridLayoutSubtree() const { + return HasRareData() ? rare_data_->GridLayoutSubtree() : nullptr; } // Return true if the two constraint spaces are similar enough that it *may* @@ -1278,25 +1274,14 @@ class CORE_EXPORT NGConstraintSpace final { target_stretch_block_sizes; } - const NGGridLayoutTrackCollection* SubgriddedColumns() const { - return GetDataUnionType() == DataUnionType::kSubgridData - ? subgrid_data_.layout_data.columns() - : nullptr; - } - - void SetSubgriddedColumns( - std::unique_ptr columns) { - EnsureSubgridData()->layout_data.SetTrackCollection(std::move(columns)); - } - - const NGGridLayoutTrackCollection* SubgriddedRows() const { + const NGGridLayoutSubtree* GridLayoutSubtree() const { return GetDataUnionType() == DataUnionType::kSubgridData - ? subgrid_data_.layout_data.rows() + ? &subgrid_data_.layout_subtree : nullptr; } - void SetSubgriddedRows(std::unique_ptr rows) { - EnsureSubgridData()->layout_data.SetTrackCollection(std::move(rows)); + void SetGridLayoutSubtree(NGGridLayoutSubtree&& grid_layout_subtree) { + EnsureSubgridData()->layout_subtree = std::move(grid_layout_subtree); } DataUnionType GetDataUnionType() const { @@ -1437,14 +1422,12 @@ class CORE_EXPORT NGConstraintSpace final { struct SubgridData { bool MaySkipLayout(const SubgridData& other) const { - return layout_data == other.layout_data; + return layout_subtree == other.layout_subtree; } - bool IsInitialForMaySkipLayout() const { - return layout_data == NGGridLayoutData(); - } + bool IsInitialForMaySkipLayout() const { return !layout_subtree; } - NGGridLayoutData layout_data; + NGGridLayoutSubtree layout_subtree; }; BlockData* EnsureBlockData() { diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h index 715c6d429caa0..a5ca10513247b 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h +++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h @@ -524,21 +524,13 @@ class CORE_EXPORT NGConstraintSpaceBuilder final { target_stretch_block_sizes); } - void SetSubgriddedColumns( - std::unique_ptr columns) { + void SetGridLayoutSubtree(NGGridLayoutSubtree&& grid_layout_subtree) { #if DCHECK_IS_ON() - DCHECK(!is_subgridded_columns_set_); - is_subgridded_columns_set_ = true; + DCHECK(!is_grid_layout_subtree_set_); + is_grid_layout_subtree_set_ = true; #endif - space_.EnsureRareData()->SetSubgriddedColumns(std::move(columns)); - } - - void SetSubgriddedRows(std::unique_ptr rows) { -#if DCHECK_IS_ON() - DCHECK(!is_subgridded_rows_set_); - is_subgridded_rows_set_ = true; -#endif - space_.EnsureRareData()->SetSubgriddedRows(std::move(rows)); + space_.EnsureRareData()->SetGridLayoutSubtree( + std::move(grid_layout_subtree)); } // Creates a new constraint space. @@ -594,8 +586,7 @@ class CORE_EXPORT NGConstraintSpaceBuilder final { bool is_table_row_data_set_ = false; bool is_table_section_data_set_ = false; bool is_line_clamp_context_set_ = false; - bool is_subgridded_columns_set_ = false; - bool is_subgridded_rows_set_ = false; + bool is_grid_layout_subtree_set_ = false; bool to_constraint_space_called_ = false; #endif diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index aa5edd072ef30..6580d5ac5a2ac 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations @@ -3487,8 +3487,10 @@ crbug.com/764235 external/wpt/css/css-grid/alignment/grid-baseline-align-001.htm crbug.com/764235 external/wpt/css/css-grid/alignment/grid-baseline-justify-001.html [ Failure ] # [css-subgrid] +crbug.com/618969 external/wpt/css/css-grid/subgrid/abs-pos-002.html [ Failure ] crbug.com/618969 external/wpt/css/css-grid/subgrid/auto-track-sizing-001.html [ Failure ] crbug.com/618969 external/wpt/css/css-grid/subgrid/auto-track-sizing-002.html [ Failure ] +crbug.com/618969 external/wpt/css/css-grid/subgrid/baseline-001.html [ Crash ] crbug.com/618969 external/wpt/css/css-grid/subgrid/grid-gap-001.html [ Failure ] crbug.com/618969 external/wpt/css/css-grid/subgrid/grid-gap-002.html [ Failure ] crbug.com/618969 external/wpt/css/css-grid/subgrid/grid-gap-003.html [ Failure ] @@ -3502,6 +3504,7 @@ crbug.com/618969 external/wpt/css/css-grid/subgrid/grid-gap-010.html [ Failure ] crbug.com/618969 external/wpt/css/css-grid/subgrid/grid-gap-011.html [ Failure ] crbug.com/618969 external/wpt/css/css-grid/subgrid/grid-gap-larger-001.html [ Failure ] crbug.com/618969 external/wpt/css/css-grid/subgrid/grid-gap-larger-002.html [ Failure ] +crbug.com/618969 external/wpt/css/css-grid/subgrid/grid-gap-normal-001.html [ Failure ] crbug.com/618969 external/wpt/css/css-grid/subgrid/grid-gap-smaller-001.html [ Failure ] crbug.com/618969 external/wpt/css/css-grid/subgrid/grid-template-computed-nogrid.html [ Failure ] crbug.com/618969 external/wpt/css/css-grid/subgrid/independent-formatting-context.html [ Failure ] @@ -3512,8 +3515,12 @@ crbug.com/618969 external/wpt/css/css-grid/subgrid/orthogonal-writing-mode-002.h crbug.com/618969 external/wpt/css/css-grid/subgrid/orthogonal-writing-mode-003.html [ Failure ] crbug.com/618969 external/wpt/css/css-grid/subgrid/orthogonal-writing-mode-004.html [ Failure ] crbug.com/618969 external/wpt/css/css-grid/subgrid/repeat-auto-fill-003.html [ Failure ] -crbug.com/618969 external/wpt/css/css-grid/subgrid/subgrid-baseline-001.html [ Failure ] +crbug.com/618969 external/wpt/css/css-grid/subgrid/repeat-auto-fill-006.html [ Failure ] +crbug.com/618969 external/wpt/css/css-grid/subgrid/subgrid-baseline-001.html [ Failure Crash ] crbug.com/618969 external/wpt/css/css-grid/subgrid/subgrid-baseline-002.html [ Crash Failure Timeout ] +crbug.com/618969 external/wpt/css/css-grid/subgrid/subgrid-baseline-003.html [ Crash ] +crbug.com/618969 external/wpt/css/css-grid/subgrid/subgrid-baseline-004.html [ Crash ] +crbug.com/618969 external/wpt/css/css-grid/subgrid/subgrid-item-block-size-001.html [ Failure ] # [css-animations]