Commit 1a9c28e7 authored by Aleks Totic's avatar Aleks Totic Committed by Commit Bot

[TablesNG] Row layout algorithm

New implementation of the row layout algorithm.
Interesting bit is an extra layout required to get the correct baseline
when cells have percentage block size descendants.

Also updated NGTableConstraintSpaceData, an oversight from previous CL.

Bug: 958381
Change-Id: I32c1b5295167e8c53fe551bddc8c141e911430a8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2376480Reviewed-by: default avatarIan Kilpatrick <ikilpatrick@chromium.org>
Reviewed-by: default avatarMorten Stenshorne <mstensho@chromium.org>
Commit-Queue: Aleks Totic <atotic@chromium.org>
Cr-Commit-Position: refs/heads/master@{#803332}
parent 29ebf872
...@@ -568,6 +568,8 @@ blink_core_sources("layout") { ...@@ -568,6 +568,8 @@ blink_core_sources("layout") {
"ng/table/ng_table_layout_algorithm_types.h", "ng/table/ng_table_layout_algorithm_types.h",
"ng/table/ng_table_layout_algorithm_utils.cc", "ng/table/ng_table_layout_algorithm_utils.cc",
"ng/table/ng_table_layout_algorithm_utils.h", "ng/table/ng_table_layout_algorithm_utils.h",
"ng/table/ng_table_row_layout_algorithm.cc",
"ng/table/ng_table_row_layout_algorithm.h",
"order_iterator.cc", "order_iterator.cc",
"order_iterator.h", "order_iterator.h",
"overflow_model.h", "overflow_model.h",
......
...@@ -316,6 +316,10 @@ class CORE_EXPORT NGConstraintSpace final { ...@@ -316,6 +316,10 @@ class CORE_EXPORT NGConstraintSpace final {
: base::nullopt; : base::nullopt;
} }
bool IsTableCellHiddenForPaint() const {
return HasRareData() ? rare_data_->IsTableCellHiddenForPaint() : false;
}
const NGTableConstraintSpaceData* TableData() const { const NGTableConstraintSpaceData* TableData() const {
return HasRareData() ? rare_data_->TableData() : nullptr; return HasRareData() ? rare_data_->TableData() : nullptr;
} }
...@@ -954,6 +958,15 @@ class CORE_EXPORT NGConstraintSpace final { ...@@ -954,6 +958,15 @@ class CORE_EXPORT NGConstraintSpace final {
table_cell_alignment_baseline; table_cell_alignment_baseline;
} }
bool IsTableCellHiddenForPaint() const {
return data_union_type == kTableCellData &&
table_cell_data_.is_hidden_for_paint;
}
void SetIsTableCellHiddenForPaint(bool is_hidden_for_paint) {
EnsureTableCellData()->is_hidden_for_paint = is_hidden_for_paint;
}
void SetTableRowData( void SetTableRowData(
scoped_refptr<const NGTableConstraintSpaceData> table_data, scoped_refptr<const NGTableConstraintSpaceData> table_data,
wtf_size_t row_index) { wtf_size_t row_index) {
...@@ -1072,7 +1085,8 @@ class CORE_EXPORT NGConstraintSpace final { ...@@ -1072,7 +1085,8 @@ class CORE_EXPORT NGConstraintSpace final {
other.table_cell_intrinsic_padding_block_end && other.table_cell_intrinsic_padding_block_end &&
table_cell_alignment_baseline == table_cell_alignment_baseline ==
other.table_cell_alignment_baseline && other.table_cell_alignment_baseline &&
table_cell_column_index == other.table_cell_column_index; table_cell_column_index == other.table_cell_column_index &&
is_hidden_for_paint == other.is_hidden_for_paint;
} }
bool IsInitialForMaySkipLayout() const { bool IsInitialForMaySkipLayout() const {
...@@ -1080,7 +1094,8 @@ class CORE_EXPORT NGConstraintSpace final { ...@@ -1080,7 +1094,8 @@ class CORE_EXPORT NGConstraintSpace final {
table_cell_intrinsic_padding_block_start == LayoutUnit() && table_cell_intrinsic_padding_block_start == LayoutUnit() &&
table_cell_intrinsic_padding_block_end == LayoutUnit() && table_cell_intrinsic_padding_block_end == LayoutUnit() &&
table_cell_column_index == kNotFound && table_cell_column_index == kNotFound &&
table_cell_alignment_baseline == base::nullopt; table_cell_alignment_baseline == base::nullopt &&
!is_hidden_for_paint;
} }
NGBoxStrut table_cell_borders; NGBoxStrut table_cell_borders;
...@@ -1088,6 +1103,7 @@ class CORE_EXPORT NGConstraintSpace final { ...@@ -1088,6 +1103,7 @@ class CORE_EXPORT NGConstraintSpace final {
LayoutUnit table_cell_intrinsic_padding_block_end; LayoutUnit table_cell_intrinsic_padding_block_end;
wtf_size_t table_cell_column_index = kNotFound; wtf_size_t table_cell_column_index = kNotFound;
base::Optional<LayoutUnit> table_cell_alignment_baseline; base::Optional<LayoutUnit> table_cell_alignment_baseline;
bool is_hidden_for_paint = false;
}; };
struct TableRowData { struct TableRowData {
......
...@@ -303,13 +303,16 @@ class CORE_EXPORT NGConstraintSpaceBuilder final { ...@@ -303,13 +303,16 @@ class CORE_EXPORT NGConstraintSpaceBuilder final {
} }
} }
void SetTableCellAlignmentBaseline(LayoutUnit table_cell_alignment_baseline) { void SetTableCellAlignmentBaseline(
const base::Optional<LayoutUnit>& table_cell_alignment_baseline) {
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
DCHECK(!is_table_cell_alignment_baseline_set_); DCHECK(!is_table_cell_alignment_baseline_set_);
is_table_cell_alignment_baseline_set_ = true; is_table_cell_alignment_baseline_set_ = true;
#endif #endif
space_.EnsureRareData()->SetTableCellAlignmentBaseline( if (is_in_parallel_flow_ && table_cell_alignment_baseline) {
table_cell_alignment_baseline); space_.EnsureRareData()->SetTableCellAlignmentBaseline(
*table_cell_alignment_baseline);
}
} }
void SetTableCellColumnIndex(wtf_size_t column_index) { void SetTableCellColumnIndex(wtf_size_t column_index) {
...@@ -320,6 +323,14 @@ class CORE_EXPORT NGConstraintSpaceBuilder final { ...@@ -320,6 +323,14 @@ class CORE_EXPORT NGConstraintSpaceBuilder final {
space_.EnsureRareData()->SetTableCellColumnIndex(column_index); space_.EnsureRareData()->SetTableCellColumnIndex(column_index);
} }
void SetIsTableCellHiddenForPaint(bool is_hidden_for_paint) {
#if DCHECK_IS_ON()
DCHECK(!is_table_cell_hidden_for_paint_set_);
is_table_cell_hidden_for_paint_set_ = true;
#endif
space_.EnsureRareData()->SetIsTableCellHiddenForPaint(is_hidden_for_paint);
}
void SetTableCellChildLayoutMode( void SetTableCellChildLayoutMode(
NGTableCellChildLayoutMode table_cell_child_layout_mode) { NGTableCellChildLayoutMode table_cell_child_layout_mode) {
space_.bitfields_.table_cell_child_layout_mode = space_.bitfields_.table_cell_child_layout_mode =
...@@ -437,6 +448,7 @@ class CORE_EXPORT NGConstraintSpaceBuilder final { ...@@ -437,6 +448,7 @@ class CORE_EXPORT NGConstraintSpaceBuilder final {
bool is_table_cell_intrinsic_padding_set_ = false; bool is_table_cell_intrinsic_padding_set_ = false;
bool is_table_cell_alignment_baseline_set_ = false; bool is_table_cell_alignment_baseline_set_ = false;
bool is_table_cell_column_index_set_ = false; bool is_table_cell_column_index_set_ = false;
bool is_table_cell_hidden_for_paint_set_ = false;
bool is_custom_layout_data_set_ = false; bool is_custom_layout_data_set_ = false;
bool is_lines_until_clamp_set_ = false; bool is_lines_until_clamp_set_ = false;
bool is_table_row_data_set_ = false; bool is_table_row_data_set_ = false;
......
...@@ -22,12 +22,16 @@ class NGTableConstraintSpaceData ...@@ -22,12 +22,16 @@ class NGTableConstraintSpaceData
public: public:
// Table grid columns are used to compute cell geometry. // Table grid columns are used to compute cell geometry.
struct ColumnLocation { struct ColumnLocation {
ColumnLocation(LayoutUnit offset, LayoutUnit inline_size) ColumnLocation(LayoutUnit offset, LayoutUnit inline_size, bool is_collapsed)
: offset(offset), inline_size(inline_size) {} : offset(offset),
LayoutUnit offset; inline_size(inline_size),
LayoutUnit inline_size; is_collapsed(is_collapsed) {}
const LayoutUnit offset;
const LayoutUnit inline_size;
const bool is_collapsed;
bool operator==(const ColumnLocation& other) const { bool operator==(const ColumnLocation& other) const {
return offset == other.offset && inline_size == other.inline_size; return offset == other.offset && inline_size == other.inline_size &&
is_collapsed == other.is_collapsed;
} }
}; };
......
// 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.
#include "third_party/blink/renderer/core/layout/ng/table/ng_table_row_layout_algorithm.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.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.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_physical_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/table/layout_ng_table_cell.h"
#include "third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_utils.h"
namespace blink {
NGTableRowLayoutAlgorithm::NGTableRowLayoutAlgorithm(
const NGLayoutAlgorithmParams& params)
: NGLayoutAlgorithm(params) {
container_builder_.SetIsNewFormattingContext(
params.space.IsNewFormattingContext());
}
MinMaxSizesResult NGTableRowLayoutAlgorithm::ComputeMinMaxSizes(
const MinMaxSizesInput&) const {
NOTREACHED(); // Table layout does not compute minmax for table row.
return MinMaxSizesResult();
}
scoped_refptr<const NGLayoutResult> NGTableRowLayoutAlgorithm::Layout() {
const NGTableConstraintSpaceData& table_data = *ConstraintSpace().TableData();
wtf_size_t row_index = ConstraintSpace().TableRowIndex();
auto CreateCellConstraintSpace = [this, &table_data](
NGBlockNode cell, wtf_size_t cell_index,
base::Optional<LayoutUnit> row_baseline,
bool row_is_collapsed,
wtf_size_t* cell_location_start_column) {
wtf_size_t start_column = table_data.cells[cell_index].start_column;
wtf_size_t end_column = std::min(start_column + cell.TableCellColspan() - 1,
table_data.column_locations.size() - 1);
*cell_location_start_column = start_column;
// When columns spanned by the cell are collapsed, cell geometry is defined
// by:
// - start edge of first non-collapsed column.
// - end edge of the last non-collapsed column.
// - if all columns are collapsed, cell_inline_size is defined by edges
// of last column. Picking last column is arbitrary, any spanned column
// would work, as all spanned columns define the same geometry: same
// location, width: 0.
while (
table_data.column_locations[*cell_location_start_column].is_collapsed &&
*cell_location_start_column < end_column)
(*cell_location_start_column)++;
wtf_size_t cell_location_end_column = end_column;
while (table_data.column_locations[cell_location_end_column].is_collapsed &&
cell_location_end_column > *cell_location_start_column)
cell_location_end_column--;
const NGTableConstraintSpaceData::Cell& cell_data =
table_data.cells[cell_index];
LayoutUnit cell_inline_size =
table_data.column_locations[cell_location_end_column].offset +
table_data.column_locations[cell_location_end_column].inline_size -
table_data.column_locations[*cell_location_start_column].offset;
LayoutUnit cell_block_size =
row_is_collapsed ? LayoutUnit() : cell_data.block_size;
NGConstraintSpaceBuilder builder(
table_data.table_writing_direction.GetWritingMode(),
cell.Style().GetWritingMode(), /* is_new_fc */ true);
builder.SetAvailableSize({cell_inline_size, cell_block_size});
builder.SetIsFixedInlineSize(true);
builder.SetIsFixedBlockSize(true);
builder.SetTextDirection(Style().Direction());
PhysicalSize icb_size = Node().InitialContainingBlockSize();
builder.SetOrthogonalFallbackInlineSize(
IsHorizontalWritingMode(
table_data.table_writing_direction.GetWritingMode())
? icb_size.height
: icb_size.width);
builder.SetPercentageResolutionSize(
LogicalSize(container_builder_.InlineSize(), kIndefiniteSize));
// Percentage block resolution size is only valid if
// cell height is specified, or table height is specified.
bool is_block_size_indefinite =
!cell_data.is_constrained &&
!table_data.treat_table_block_size_as_constrained;
if (is_block_size_indefinite)
builder.SetIsFixedBlockSizeIndefinite(true);
builder.SetIsTableCell(/* is_table_cell */ true,
/* is_legacy_table_cell */ false);
builder.SetTableCellBorders(cell_data.border_box_borders);
builder.SetTableCellAlignmentBaseline(row_baseline);
builder.SetTableCellColumnIndex(start_column);
builder.SetNeedsBaseline(true);
builder.SetIsTableCellHiddenForPaint(
table_data.column_locations[*cell_location_start_column].is_collapsed &&
*cell_location_start_column == cell_location_end_column);
return builder.ToConstraintSpace();
};
const NGTableConstraintSpaceData::Row& row = table_data.rows[row_index];
// Cell with perecentage block size descendants can layout with
// size that differs from its intrinsic size. This might cause
// row baseline to move, if cell was baseline-aligned.
// To compute correct baseline, we need to do an initial layout pass.
WritingMode table_writing_mode = ConstraintSpace().GetWritingMode();
LayoutUnit row_baseline = row.baseline;
wtf_size_t cell_index = row.start_cell_index;
if (row.has_baseline_aligned_percentage_block_size_descendants) {
for (NGBlockNode cell = To<NGBlockNode>(Node().FirstChild()); cell;
cell = To<NGBlockNode>(cell.NextSibling()), ++cell_index) {
bool is_parallel = IsParallelWritingMode(table_writing_mode,
cell.Style().GetWritingMode());
if (!NGTableAlgorithmUtils::IsBaseline(cell.Style().VerticalAlign()) ||
!is_parallel)
continue;
wtf_size_t cell_location_start_column;
NGConstraintSpace cell_constraint_space = CreateCellConstraintSpace(
cell, cell_index, base::nullopt, row.is_collapsed,
&cell_location_start_column);
scoped_refptr<const NGLayoutResult> layout_result =
cell.Layout(cell_constraint_space);
const NGBoxFragment fragment(
table_data.table_writing_direction.GetWritingMode(),
table_data.table_writing_direction.Direction(),
To<NGPhysicalBoxFragment>(layout_result->PhysicalFragment()));
LayoutUnit baseline = fragment.FirstBaselineOrSynthesize();
row_baseline = std::max(row_baseline, baseline);
}
}
// Generate cell fragments.
base::Optional<LayoutUnit> reported_row_baseline;
cell_index = row.start_cell_index;
for (NGBlockNode cell = To<NGBlockNode>(Node().FirstChild()); cell;
cell = To<NGBlockNode>(cell.NextSibling()), ++cell_index) {
wtf_size_t cell_location_start_column;
NGConstraintSpace cell_constraint_space = CreateCellConstraintSpace(
cell, cell_index, row_baseline, row.is_collapsed,
&cell_location_start_column);
scoped_refptr<const NGLayoutResult> cell_result =
cell.Layout(cell_constraint_space);
LogicalOffset cell_offset(
table_data.column_locations[cell_location_start_column].offset -
table_data.table_border_spacing.inline_size,
LayoutUnit());
container_builder_.AddResult(*cell_result, cell_offset);
if (NGTableAlgorithmUtils::IsBaseline(cell.Style().VerticalAlign())) {
const NGBoxFragment fragment(
table_data.table_writing_direction.GetWritingMode(),
table_data.table_writing_direction.Direction(),
To<NGPhysicalBoxFragment>(cell_result->PhysicalFragment()));
reported_row_baseline =
std::max(reported_row_baseline.value_or(LayoutUnit::Min()),
fragment.FirstBaselineOrSynthesize());
}
}
container_builder_.SetFragmentBlockSize(row.block_size);
container_builder_.SetBaseline(
reported_row_baseline.value_or(row.block_size));
if (row.is_collapsed)
container_builder_.SetIsHiddenForPaint(true);
NGOutOfFlowLayoutPart(Node(), ConstraintSpace(), &container_builder_).Run();
return container_builder_.ToBoxFragment();
}
} // namespace blink
// 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_TABLE_NG_TABLE_ROW_LAYOUT_ALGORITHM_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_TABLE_NG_TABLE_ROW_LAYOUT_ALGORITHM_H_
#include "third_party/blink/renderer/core/layout/ng/ng_layout_algorithm.h"
#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h"
namespace blink {
class NGBlockNode;
class NGBlockBreakToken;
class CORE_EXPORT NGTableRowLayoutAlgorithm
: public NGLayoutAlgorithm<NGBlockNode,
NGBoxFragmentBuilder,
NGBlockBreakToken> {
public:
explicit NGTableRowLayoutAlgorithm(const NGLayoutAlgorithmParams& params);
scoped_refptr<const NGLayoutResult> Layout() override;
MinMaxSizesResult ComputeMinMaxSizes(const MinMaxSizesInput&) const override;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_TABLE_NG_TABLE_ROW_LAYOUT_ALGORITHM_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