Commit c0c6e68e authored by Kurt Catti-Schmidt's avatar Kurt Catti-Schmidt Committed by Commit Bot

[GridNG] Measuring stage of NGGridLayoutAlgorithm

This change builds upon the previous work in NGGridLayoutAlgorithm
to actually perform measuring on the grid items.

The next step in the grid algorithm is to determine track column
widths. Since column-widths can be content-based (min-content and
max-content), these measurements will be necessary at that point.

Much like my previous change, this is validated using unit tests, as
we cannot currently test end-to-end grid layout until we have more
stages of the grid algorithm completed.

Note that percentage resolution is currently incorrect. It will require
another layout pass with additional sizing data. This is noted in the
incorrect test result.

Bug: 1045599
Change-Id: Ic10a8522a16e70792e2299dfe3d8eda0231ff877
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2257403Reviewed-by: default avatarChristian Biesinger <cbiesinger@chromium.org>
Reviewed-by: default avatarIan Kilpatrick <ikilpatrick@chromium.org>
Commit-Queue: Kurt Catti-Schmidt <kschmi@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#786110}
parent ceb1c173
...@@ -65,25 +65,61 @@ void NGGridLayoutAlgorithm::ConstructAndAppendGridItems() { ...@@ -65,25 +65,61 @@ void NGGridLayoutAlgorithm::ConstructAndAppendGridItems() {
void NGGridLayoutAlgorithm::ConstructAndAppendGridItem( void NGGridLayoutAlgorithm::ConstructAndAppendGridItem(
const NGBlockNode& node) { const NGBlockNode& node) {
GridItem item; items_.emplace_back(MeasureGridItem(node));
item.constraint_space = BuildSpaceForMeasure(node);
items_.emplace_back(item);
} }
NGConstraintSpace NGGridLayoutAlgorithm::BuildSpaceForMeasure( NGGridLayoutAlgorithm::GridItemData NGGridLayoutAlgorithm::MeasureGridItem(
const NGBlockNode& grid_item) { const NGBlockNode& node) {
const ComputedStyle& child_style = grid_item.Style(); // Before we take track sizing into account for column width contributions,
// have all child inline and min/max sizes measured for content-based width
// resolution.
NGConstraintSpace constraint_space = BuildSpaceForGridItem(node);
const ComputedStyle& child_style = node.Style();
bool is_orthogonal_flow_root = !IsParallelWritingMode(
ConstraintSpace().GetWritingMode(), child_style.GetWritingMode());
GridItemData grid_item_data;
// Children with orthogonal writing modes require a full layout pass to
// determine inline size.
if (is_orthogonal_flow_root) {
scoped_refptr<const NGLayoutResult> result = node.Layout(constraint_space);
grid_item_data.inline_size = NGFragment(ConstraintSpace().GetWritingMode(),
result->PhysicalFragment())
.InlineSize();
} else {
NGBoxStrut border_padding_in_child_writing_mode =
ComputeBorders(constraint_space, child_style) +
ComputePadding(constraint_space, child_style);
grid_item_data.inline_size = ComputeInlineSizeForFragment(
constraint_space, node, border_padding_in_child_writing_mode);
}
grid_item_data.margins =
ComputeMarginsFor(constraint_space, child_style, ConstraintSpace());
grid_item_data.min_max_sizes =
node.ComputeMinMaxSizes(
ConstraintSpace().GetWritingMode(),
MinMaxSizesInput(child_percentage_size_.block_size,
MinMaxSizesType::kContent),
&constraint_space)
.sizes;
return grid_item_data;
}
NGConstraintSpace NGGridLayoutAlgorithm::BuildSpaceForGridItem(
const NGBlockNode& node) const {
NGConstraintSpaceBuilder space_builder(ConstraintSpace(), NGConstraintSpaceBuilder space_builder(ConstraintSpace(),
child_style.GetWritingMode(), node.Style().GetWritingMode(),
/* is_new_fc */ true); node.CreatesNewFormattingContext());
space_builder.SetCacheSlot(NGCacheSlot::kMeasure); space_builder.SetCacheSlot(NGCacheSlot::kMeasure);
space_builder.SetIsPaintedAtomically(true); space_builder.SetIsPaintedAtomically(true);
// TODO(kschmi): - do layout/measuring and handle non-fixed sizes here.
space_builder.SetAvailableSize(ChildAvailableSize()); space_builder.SetAvailableSize(ChildAvailableSize());
space_builder.SetPercentageResolutionSize(child_percentage_size_); space_builder.SetPercentageResolutionSize(child_percentage_size_);
space_builder.SetTextDirection(child_style.Direction()); space_builder.SetTextDirection(node.Style().Direction());
space_builder.SetIsShrinkToFit(node.Style().LogicalWidth().IsAuto());
return space_builder.ToConstraintSpace(); return space_builder.ToConstraintSpace();
} }
......
...@@ -28,12 +28,20 @@ class CORE_EXPORT NGGridLayoutAlgorithm ...@@ -28,12 +28,20 @@ class CORE_EXPORT NGGridLayoutAlgorithm
const NGGridBlockTrackCollection& ColumnTrackCollection() const; const NGGridBlockTrackCollection& ColumnTrackCollection() const;
const NGGridBlockTrackCollection& RowTrackCollection() const; const NGGridBlockTrackCollection& RowTrackCollection() const;
private:
struct GridItemData {
LayoutUnit inline_size;
MinMaxSizes min_max_sizes;
NGBoxStrut margins;
};
private: private:
friend class NGGridLayoutAlgorithmTest; friend class NGGridLayoutAlgorithmTest;
void ConstructAndAppendGridItems(); void ConstructAndAppendGridItems();
void ConstructAndAppendGridItem(const NGBlockNode& node); void ConstructAndAppendGridItem(const NGBlockNode& node);
NGConstraintSpace BuildSpaceForMeasure(const NGBlockNode& grid_item); GridItemData MeasureGridItem(const NGBlockNode& node);
NGConstraintSpace BuildSpaceForGridItem(const NGBlockNode& node) const;
// Sets the specified tracks for row and column track lists. // Sets the specified tracks for row and column track lists.
void BuildTrackLists(); void BuildTrackLists();
...@@ -64,10 +72,7 @@ class CORE_EXPORT NGGridLayoutAlgorithm ...@@ -64,10 +72,7 @@ class CORE_EXPORT NGGridLayoutAlgorithm
}; };
GridLayoutAlgorithmState state_; GridLayoutAlgorithmState state_;
struct GridItem { Vector<GridItemData> items_;
NGConstraintSpace constraint_space;
};
NGGridTrackList column_track_list_; NGGridTrackList column_track_list_;
NGGridTrackList row_track_list_; NGGridTrackList row_track_list_;
NGGridBlockTrackCollection column_track_collection_; NGGridBlockTrackCollection column_track_collection_;
...@@ -77,8 +82,6 @@ class CORE_EXPORT NGGridLayoutAlgorithm ...@@ -77,8 +82,6 @@ class CORE_EXPORT NGGridLayoutAlgorithm
wtf_size_t automatic_row_repetitions_for_testing = wtf_size_t automatic_row_repetitions_for_testing =
NGGridBlockTrackCollection::kInvalidRangeIndex; NGGridBlockTrackCollection::kInvalidRangeIndex;
Vector<GridItem> items_;
LogicalSize child_percentage_size_; LogicalSize child_percentage_size_;
}; };
......
...@@ -24,17 +24,32 @@ class NGGridLayoutAlgorithmTest ...@@ -24,17 +24,32 @@ class NGGridLayoutAlgorithmTest
// Helper methods to access private data on NGGridLayoutAlgorithm. This class // Helper methods to access private data on NGGridLayoutAlgorithm. This class
// is a friend of NGGridLayoutAlgorithm but the individual tests are not. // is a friend of NGGridLayoutAlgorithm but the individual tests are not.
size_t GridItemSize(NGGridLayoutAlgorithm& algorithm) { size_t GridItemCount(NGGridLayoutAlgorithm& algorithm) {
return algorithm.items_.size(); return algorithm.items_.size();
} }
Vector<NGConstraintSpace> GridItemConstraintSpaces( Vector<LayoutUnit> GridItemInlineSizes(NGGridLayoutAlgorithm& algorithm) {
NGGridLayoutAlgorithm& algorithm) { Vector<LayoutUnit> results;
Vector<NGConstraintSpace> constraint_spaces;
for (auto& item : algorithm.items_) { for (auto& item : algorithm.items_) {
constraint_spaces.push_back(NGConstraintSpace(item.constraint_space)); results.push_back(item.inline_size);
} }
return constraint_spaces; return results;
}
Vector<LayoutUnit> GridItemInlineMarginSum(NGGridLayoutAlgorithm& algorithm) {
Vector<LayoutUnit> results;
for (auto& item : algorithm.items_) {
results.push_back(item.margins.InlineSum());
}
return results;
}
Vector<MinMaxSizes> GridItemMinMaxSizes(NGGridLayoutAlgorithm& algorithm) {
Vector<MinMaxSizes> results;
for (auto& item : algorithm.items_) {
results.push_back(item.min_max_sizes);
}
return results;
} }
void SetAutoTrackRepeat(NGGridLayoutAlgorithm& algorithm, void SetAutoTrackRepeat(NGGridLayoutAlgorithm& algorithm,
...@@ -50,39 +65,126 @@ TEST_F(NGGridLayoutAlgorithmTest, NGGridLayoutAlgorithmMeasuring) { ...@@ -50,39 +65,126 @@ TEST_F(NGGridLayoutAlgorithmTest, NGGridLayoutAlgorithmMeasuring) {
if (!RuntimeEnabledFeatures::LayoutNGGridEnabled()) if (!RuntimeEnabledFeatures::LayoutNGGridEnabled())
return; return;
LoadAhem();
SetBodyInnerHTML(R"HTML( SetBodyInnerHTML(R"HTML(
<style> <style>
body {
font: 10px/1 Ahem;
}
#grid1 { #grid1 {
display: grid; display: grid;
grid-template-columns: 100px 100px; width: 200px;
grid-template-rows: 100px 100px; height: 200px;
grid-template-columns: min-content min-content min-content;
grid-template-rows: 100px 100px 100px;
} }
/* Basic fixed width specified, evaluates to 150px (50px width + 50px
margin-left + 50px margin-right). */
#cell1 { #cell1 {
grid-column: 1; grid-column: 1;
grid-row: 1; grid-row: 1;
width: 50px; width: 50px;
height: 50px;
margin: 50px;
} }
/* 100px content, with margin/border/padding. Evaluates to 146px
(100px width + 15px margin-left + 15px margin-righ + 5px border-left +
5px border-right + 3px padding-left + 3px padding-right). */
#cell2 { #cell2 {
grid-column: 2; grid-column: 2;
grid-row: 1; grid-row: 1;
width: 50px; min-width: 50px;
height: 100px;
border: 5px solid black;
margin: 15px;
padding: 3px;
} }
/* % resolution, needs another pass for the real computed value. For now,
this is evaluated based on the 200px grid content, so it evaluates
to the (currently incorrect) value of 50% of 200px = 100px. */
#cell3 { #cell3 {
grid-column: 3;
grid-row: 1;
width: 50%;
height: 50%;
}
/* 'auto' sizing, with fixed 100px child, evaluates to 100px. */
#cell4 {
grid-column: 1; grid-column: 1;
grid-row: 2; grid-row: 2;
width: 50px; width: auto;
height: auto;
} }
#cell4 { /* 'auto' sizing replaced content, evaluates to default replaced width of
300px. */
#cell5 {
grid-column: 2; grid-column: 2;
grid-row: 2; grid-row: 2;
width: 50px; width: auto;
height: auto;
}
/* 'auto' sizing replaced content, max-width restricts 300px size to
evaluate to 100px. */
#cell6 {
grid-column: 3;
grid-row: 2;
width: auto;
height: auto;
max-width: 100px;
}
/* 'auto' sizing replaced content, min-width expands to 400px, which
in a total offset size of 410 (400px + 5px margin-left + 5px
margin-right). */
#cell7 {
grid-column: 1;
grid-row: 3;
width: auto;
height: auto;
margin: 5px;
min-width: 400px;
}
/* 'auto' sizing with 100px content, min-width and margin evaluates to
100px + 50px margin-left + 50px margin-right = 200px. */
#cell8 {
grid-column: 2;
grid-row: 3;
width: auto;
height: auto;
margin: 50px;
min-width: 100px;
}
/* 'auto' sizing with text content and vertical writing mode. In horizontal
writing-modes, this would be an expected inline size of 40px (at 10px
per character), but since it's set to a vertical writing mode, the
expected width is 10px (at 10px per character). */
#cell9 {
grid-column: 3;
grid-row: 3;
width: auto;
height: auto;
writing-mode: vertical-lr;
}
#block {
width: 100px;
height: 100px;
} }
</style> </style>
<div id="grid1"> <div id="grid1">
<div id="cell1">Cell 1</div> <div id="cell1">Cell 1</div>
<div id="cell2">Cell 2</div> <div id="cell2"><div id="block"></div></div>
<div id="cell3">Cell 3</div> <div id="cell3">Cell 3</div>
<div id="cell4">Cell 4</div> <div id="cell4"><div id="block"></div></div>
<svg id="cell5">
<rect width="100%" height="100%" fill="blue" />
</svg>
<svg id="cell6">
<rect width="100%" height="100%" fill="blue" />
</svg>
<svg id="cell7">
<rect width="100%" height="100%" fill="blue" />
</svg>
<div id="cell8"><div id="block"></div></div>
<div id="cell9">Text</div>
</div> </div>
)HTML"); )HTML");
...@@ -90,23 +192,55 @@ TEST_F(NGGridLayoutAlgorithmTest, NGGridLayoutAlgorithmMeasuring) { ...@@ -90,23 +192,55 @@ TEST_F(NGGridLayoutAlgorithmTest, NGGridLayoutAlgorithmMeasuring) {
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace( NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
WritingMode::kHorizontalTb, TextDirection::kLtr, WritingMode::kHorizontalTb, TextDirection::kLtr,
LogicalSize(LayoutUnit(100), LayoutUnit(100)), false, true); LogicalSize(LayoutUnit(200), LayoutUnit(200)), false, true);
NGFragmentGeometry fragment_geometry = NGFragmentGeometry fragment_geometry =
CalculateInitialFragmentGeometry(space, node); CalculateInitialFragmentGeometry(space, node);
NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space}); NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space});
EXPECT_EQ(GridItemSize(algorithm), 0U); EXPECT_EQ(GridItemCount(algorithm), 0U);
SetAutoTrackRepeat(algorithm, 5, 5); SetAutoTrackRepeat(algorithm, 5, 5);
algorithm.Layout(); algorithm.Layout();
EXPECT_EQ(GridItemSize(algorithm), 4U); EXPECT_EQ(GridItemCount(algorithm), 9U);
Vector<NGConstraintSpace> constraint_spaces = Vector<LayoutUnit> actual_inline_sizes = GridItemInlineSizes(algorithm);
GridItemConstraintSpaces(algorithm); EXPECT_EQ(GridItemCount(algorithm), actual_inline_sizes.size());
EXPECT_EQ(GridItemSize(algorithm), constraint_spaces.size()); LayoutUnit expected_inline_sizes[] = {
for (auto& constraint_space : constraint_spaces) { LayoutUnit(50), LayoutUnit(116), LayoutUnit(100),
EXPECT_EQ(constraint_space.AvailableSize().inline_size.ToInt(), 100); LayoutUnit(100), LayoutUnit(300), LayoutUnit(100),
LayoutUnit(400), LayoutUnit(100), LayoutUnit(10)};
Vector<LayoutUnit> actual_inline_margin_sums =
GridItemInlineMarginSum(algorithm);
EXPECT_EQ(GridItemCount(algorithm), actual_inline_margin_sums.size());
LayoutUnit expected_inline_margin_sums[] = {
LayoutUnit(100), LayoutUnit(30), LayoutUnit(0),
LayoutUnit(0), LayoutUnit(0), LayoutUnit(0),
LayoutUnit(10), LayoutUnit(100), LayoutUnit(0)};
Vector<MinMaxSizes> actual_min_max_sizes = GridItemMinMaxSizes(algorithm);
EXPECT_EQ(GridItemCount(algorithm), actual_min_max_sizes.size());
MinMaxSizes expected_min_max_sizes[] = {
{LayoutUnit(40), LayoutUnit(60)}, {LayoutUnit(116), LayoutUnit(116)},
{LayoutUnit(40), LayoutUnit(60)}, {LayoutUnit(100), LayoutUnit(100)},
{LayoutUnit(300), LayoutUnit(300)}, {LayoutUnit(300), LayoutUnit(300)},
{LayoutUnit(300), LayoutUnit(300)}, {LayoutUnit(100), LayoutUnit(100)},
{LayoutUnit(40), LayoutUnit(40)}};
for (size_t i = 0; i < GridItemCount(algorithm); ++i) {
EXPECT_EQ(actual_inline_sizes[i], expected_inline_sizes[i])
<< " index: " << i;
EXPECT_EQ(actual_inline_margin_sums[i], expected_inline_margin_sums[i])
<< " index: " << i;
EXPECT_EQ(actual_min_max_sizes[i].min_size,
expected_min_max_sizes[i].min_size)
<< " index: " << i;
EXPECT_EQ(actual_min_max_sizes[i].max_size,
expected_min_max_sizes[i].max_size)
<< " index: " << i;
} }
} }
...@@ -140,10 +274,10 @@ TEST_F(NGGridLayoutAlgorithmTest, NGGridLayoutAlgorithmRanges) { ...@@ -140,10 +274,10 @@ TEST_F(NGGridLayoutAlgorithmTest, NGGridLayoutAlgorithmRanges) {
CalculateInitialFragmentGeometry(space, node); CalculateInitialFragmentGeometry(space, node);
NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space}); NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space});
EXPECT_EQ(GridItemSize(algorithm), 0U); EXPECT_EQ(GridItemCount(algorithm), 0U);
SetAutoTrackRepeat(algorithm, 5, 5); SetAutoTrackRepeat(algorithm, 5, 5);
algorithm.Layout(); algorithm.Layout();
EXPECT_EQ(GridItemSize(algorithm), 4U); EXPECT_EQ(GridItemCount(algorithm), 4U);
NGGridTrackCollectionBase::RangeRepeatIterator row_iterator( NGGridTrackCollectionBase::RangeRepeatIterator row_iterator(
&algorithm.RowTrackCollection(), 0u); &algorithm.RowTrackCollection(), 0u);
...@@ -205,10 +339,10 @@ TEST_F(NGGridLayoutAlgorithmTest, NGGridLayoutAlgorithmRangesWithAutoRepeater) { ...@@ -205,10 +339,10 @@ TEST_F(NGGridLayoutAlgorithmTest, NGGridLayoutAlgorithmRangesWithAutoRepeater) {
CalculateInitialFragmentGeometry(space, node); CalculateInitialFragmentGeometry(space, node);
NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space}); NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space});
EXPECT_EQ(GridItemSize(algorithm), 0U); EXPECT_EQ(GridItemCount(algorithm), 0U);
SetAutoTrackRepeat(algorithm, 5, 5); SetAutoTrackRepeat(algorithm, 5, 5);
algorithm.Layout(); algorithm.Layout();
EXPECT_EQ(GridItemSize(algorithm), 4U); EXPECT_EQ(GridItemCount(algorithm), 4U);
NGGridTrackCollectionBase::RangeRepeatIterator row_iterator( NGGridTrackCollectionBase::RangeRepeatIterator row_iterator(
&algorithm.RowTrackCollection(), 0u); &algorithm.RowTrackCollection(), 0u);
...@@ -286,10 +420,10 @@ TEST_F(NGGridLayoutAlgorithmTest, NGGridLayoutAlgorithmRangesImplicit) { ...@@ -286,10 +420,10 @@ TEST_F(NGGridLayoutAlgorithmTest, NGGridLayoutAlgorithmRangesImplicit) {
CalculateInitialFragmentGeometry(space, node); CalculateInitialFragmentGeometry(space, node);
NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space}); NGGridLayoutAlgorithm algorithm({node, fragment_geometry, space});
EXPECT_EQ(GridItemSize(algorithm), 0U); EXPECT_EQ(GridItemCount(algorithm), 0U);
SetAutoTrackRepeat(algorithm, 5, 5); SetAutoTrackRepeat(algorithm, 5, 5);
algorithm.Layout(); algorithm.Layout();
EXPECT_EQ(GridItemSize(algorithm), 4U); EXPECT_EQ(GridItemCount(algorithm), 4U);
NGGridTrackCollectionBase::RangeRepeatIterator column_iterator( NGGridTrackCollectionBase::RangeRepeatIterator column_iterator(
&algorithm.ColumnTrackCollection(), 0u); &algorithm.ColumnTrackCollection(), 0u);
......
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