Index: third_party/WebKit/Source/core/layout/LayoutTable.cpp |
diff --git a/third_party/WebKit/Source/core/layout/LayoutTable.cpp b/third_party/WebKit/Source/core/layout/LayoutTable.cpp |
index 3e64f7298ab2b4bdaaceb428a285793cb3c289cd..eef3dd5c0faaf05b0e396947cf4ccfb07371c292 100644 |
--- a/third_party/WebKit/Source/core/layout/LayoutTable.cpp |
+++ b/third_party/WebKit/Source/core/layout/LayoutTable.cpp |
@@ -58,10 +58,10 @@ LayoutTable::LayoutTable(Element* element) |
first_body_(nullptr), |
collapsed_borders_valid_(false), |
needs_invalidate_collapsed_borders_for_all_cells_(false), |
- has_col_elements_(false), |
needs_section_recalc_(false), |
column_logical_width_changed_(false), |
- column_layout_objects_valid_(false), |
+ // This is initially true because we don't have column elements initially. |
+ cols_at_effective_columns_valid_(true), |
no_cell_colspan_at_least_(0), |
h_spacing_(0), |
v_spacing_(0), |
@@ -136,10 +136,7 @@ static inline bool NeedsTableSection(LayoutObject* object) { |
void LayoutTable::AddChild(LayoutObject* child, LayoutObject* before_child) { |
bool wrap_in_anonymous_section = !child->IsOutOfFlowPositioned(); |
- if (child->IsTableCaption()) { |
- wrap_in_anonymous_section = false; |
- } else if (child->IsLayoutTableCol()) { |
- has_col_elements_ = true; |
+ if (child->IsTableCaption() || child->IsLayoutTableCol()) { |
wrap_in_anonymous_section = false; |
} else if (child->IsTableSection()) { |
switch (child->Style()->Display()) { |
@@ -236,21 +233,17 @@ void LayoutTable::RemoveCaption(const LayoutTableCaption* old_caption) { |
captions_.erase(index); |
} |
-void LayoutTable::InvalidateCachedColumns() { |
- column_layout_objects_valid_ = false; |
- column_layout_objects_.resize(0); |
+void LayoutTable::InvalidateColsAtEffectiveColumns() const { |
+ cols_at_effective_columns_valid_ = false; |
+ cols_at_effective_columns_ = nullptr; |
} |
void LayoutTable::AddColumn(const LayoutTableCol*) { |
- InvalidateCachedColumns(); |
+ InvalidateColsAtEffectiveColumns(); |
} |
void LayoutTable::RemoveColumn(const LayoutTableCol*) { |
- InvalidateCachedColumns(); |
- // We don't really need to recompute our sections, but we need to update our |
- // column count and whether we have a column. Currently, we only have one |
- // size-fit-all flag but we may have to consider splitting it. |
- SetNeedsSectionRecalc(); |
+ InvalidateColsAtEffectiveColumns(); |
} |
bool LayoutTable::IsLogicalWidthAuto() const { |
@@ -1009,6 +1002,8 @@ void LayoutTable::SplitEffectiveColumn(unsigned index, unsigned first_span) { |
} |
effective_column_positions_.Grow(NumEffectiveColumns() + 1); |
+ |
+ InvalidateColsAtEffectiveColumns(); |
} |
void LayoutTable::AppendEffectiveColumn(unsigned span) { |
@@ -1038,6 +1033,8 @@ void LayoutTable::AppendEffectiveColumn(unsigned span) { |
} |
effective_column_positions_.Grow(NumEffectiveColumns() + 1); |
+ |
+ InvalidateColsAtEffectiveColumns(); |
} |
LayoutTableCol* LayoutTable::FirstColumn() const { |
@@ -1050,60 +1047,72 @@ LayoutTableCol* LayoutTable::FirstColumn() const { |
return nullptr; |
} |
-void LayoutTable::UpdateColumnCache() const { |
- DCHECK(has_col_elements_); |
- DCHECK(column_layout_objects_.IsEmpty()); |
- DCHECK(!column_layout_objects_valid_); |
+LayoutTableCol* LayoutTable::FirstInnermostColumn() const { |
+ auto* col = FirstColumn(); |
+ return !col || col->IsInnermost() ? col : col->NextInnermostColumn(); |
+} |
- for (LayoutTableCol* column_layout_object = FirstColumn(); |
- column_layout_object; |
- column_layout_object = column_layout_object->NextColumn()) { |
- if (column_layout_object->IsTableColumnGroupWithColumnChildren()) |
- continue; |
- column_layout_objects_.push_back(column_layout_object); |
- } |
- column_layout_objects_valid_ = true; |
-} |
- |
-LayoutTable::ColAndColGroup LayoutTable::SlowColElementAtAbsoluteColumn( |
- unsigned absolute_column_index) const { |
- DCHECK(has_col_elements_); |
- |
- if (!column_layout_objects_valid_) |
- UpdateColumnCache(); |
- |
- unsigned column_count = 0; |
- for (unsigned i = 0; i < column_layout_objects_.size(); i++) { |
- LayoutTableCol* column_layout_object = column_layout_objects_[i]; |
- DCHECK(!column_layout_object->IsTableColumnGroupWithColumnChildren()); |
- unsigned span = column_layout_object->Span(); |
- unsigned start_col = column_count; |
- DCHECK_GE(span, 1u); |
- unsigned end_col = column_count + span - 1; |
- column_count += span; |
- if (column_count > absolute_column_index) { |
- ColAndColGroup col_and_col_group; |
- bool is_at_start_edge = start_col == absolute_column_index; |
- bool is_at_end_edge = end_col == absolute_column_index; |
- if (column_layout_object->IsTableColumnGroup()) { |
- col_and_col_group.colgroup = column_layout_object; |
- col_and_col_group.adjoins_start_border_of_col_group = is_at_start_edge; |
- col_and_col_group.adjoins_end_border_of_col_group = is_at_end_edge; |
- } else { |
- col_and_col_group.col = column_layout_object; |
- col_and_col_group.colgroup = |
- column_layout_object->EnclosingColumnGroup(); |
- if (col_and_col_group.colgroup) { |
- col_and_col_group.adjoins_start_border_of_col_group = |
- is_at_start_edge && !col_and_col_group.col->PreviousSibling(); |
- col_and_col_group.adjoins_end_border_of_col_group = |
- is_at_end_edge && !col_and_col_group.col->NextSibling(); |
- } |
+void LayoutTable::UpdateColsAtEffectiveColumns() const { |
+ DCHECK(!NeedsSectionRecalc()); |
+ DCHECK(!cols_at_effective_columns_valid_); |
+ DCHECK(!cols_at_effective_columns_); |
+ |
+ cols_at_effective_columns_valid_ = true; |
+ auto* col = FirstInnermostColumn(); |
+ if (!col) |
+ return; |
+ |
+ cols_at_effective_columns_ = WTF::MakeUnique<Vector<ColAndColGroup>>(); |
+ |
+ unsigned absolute_column_index = 0; |
+ unsigned col_absolute_column_index = 0; |
+ unsigned next_col_absolute_column_index = col->Span(); |
+ for (unsigned effective_column_index = 0; |
+ col && effective_column_index < effective_columns_.size(); |
+ effective_column_index++) { |
+ unsigned next_absolute_column_index = |
+ absolute_column_index + effective_columns_[effective_column_index].span; |
+ bool is_at_start_edge = absolute_column_index == col_absolute_column_index; |
+ bool is_at_end_edge = |
+ next_absolute_column_index == next_col_absolute_column_index; |
+ ColAndColGroup col_and_col_group; |
+ if (col->IsTableColumnGroup()) { |
+ col_and_col_group.colgroup = col; |
+ col_and_col_group.adjoins_start_border_of_col_group = is_at_start_edge; |
+ col_and_col_group.adjoins_end_border_of_col_group = is_at_end_edge; |
+ } else { |
+ col_and_col_group.col = col; |
+ col_and_col_group.colgroup = col->EnclosingColumnGroup(); |
+ if (col_and_col_group.colgroup) { |
+ col_and_col_group.adjoins_start_border_of_col_group = |
+ is_at_start_edge && !col->PreviousSibling(); |
+ col_and_col_group.adjoins_end_border_of_col_group = |
+ is_at_end_edge && !col->NextSibling(); |
} |
- return col_and_col_group; |
} |
+ |
+ // Skip useless col objects that don't generate effective columns. |
+ while (next_absolute_column_index >= next_col_absolute_column_index) { |
+ if (next_col_absolute_column_index == next_absolute_column_index && |
+ !col_and_col_group.adjoins_end_border_of_col_group && |
+ col_and_col_group.colgroup == col->EnclosingColumnGroup()) { |
+ // Special case: the effective column adjoins the end border of |
+ // col_and_col_group.colgroup though it doesn't adjoin the end border of |
+ // col_and_col_group.col. All subsequent cols of col_and_col_group.col |
+ // don't generate new effective columns. |
+ col_and_col_group.adjoins_end_border_of_col_group = true; |
+ } |
+ |
+ col_absolute_column_index = next_col_absolute_column_index; |
+ col = col->NextInnermostColumn(); |
+ if (!col) |
+ break; |
+ next_col_absolute_column_index += col->Span(); |
+ } |
+ |
+ absolute_column_index = next_absolute_column_index; |
+ cols_at_effective_columns_->push_back(col_and_col_group); |
} |
- return ColAndColGroup(); |
} |
void LayoutTable::RecalcSections() const { |
@@ -1112,17 +1121,12 @@ void LayoutTable::RecalcSections() const { |
head_ = nullptr; |
foot_ = nullptr; |
first_body_ = nullptr; |
- has_col_elements_ = false; |
// We need to get valid pointers to caption, head, foot and first body again |
LayoutObject* next_sibling; |
for (LayoutObject* child = FirstChild(); child; child = next_sibling) { |
next_sibling = child->NextSibling(); |
switch (child->Style()->Display()) { |
- case EDisplay::kTableColumn: |
- case EDisplay::kTableColumnGroup: |
- has_col_elements_ = true; |
- break; |
case EDisplay::kTableHeaderGroup: |
if (child->IsTableSection()) { |
LayoutTableSection* section = ToLayoutTableSection(child); |
@@ -1163,7 +1167,7 @@ void LayoutTable::RecalcSections() const { |
child = child->NextSibling()) { |
if (child->IsTableSection()) { |
LayoutTableSection* section = ToLayoutTableSection(child); |
- unsigned section_cols = section->NumEffectiveColumns(); |
+ unsigned section_cols = section->MaxNumEffectiveColumnsOfRows(); |
if (section_cols > max_cols) |
max_cols = section_cols; |
} |
@@ -1173,6 +1177,8 @@ void LayoutTable::RecalcSections() const { |
effective_column_positions_.resize(max_cols + 1); |
no_cell_colspan_at_least_ = CalcNoCellColspanAtLeast(); |
+ InvalidateColsAtEffectiveColumns(); |
+ |
DCHECK(SelfNeedsLayout()); |
needs_section_recalc_ = false; |
@@ -1198,7 +1204,7 @@ int LayoutTable::CalcBorderStart() const { |
// TODO(dgrogan): This logic doesn't properly account for the first column in |
// the first column-group case. |
if (LayoutTableCol* column = |
- ColElementAtAbsoluteColumn(0).InnermostColOrColGroup()) { |
+ ColAndColGroupAtEffectiveColumn(0).InnermostColOrColGroup()) { |
// FIXME: We don't account for direction on columns and column groups. |
const BorderValue& column_adjoining_border = column->Style()->BorderStart(); |
if (column_adjoining_border.Style() == EBorderStyle::kHidden) |
@@ -1266,8 +1272,8 @@ int LayoutTable::CalcBorderEnd() const { |
// TODO(dgrogan): This logic doesn't properly account for the last column in |
// the last column-group case. |
- if (LayoutTableCol* column = |
- ColElementAtAbsoluteColumn(end_column).InnermostColOrColGroup()) { |
+ if (LayoutTableCol* column = ColAndColGroupAtEffectiveColumn(end_column) |
+ .InnermostColOrColGroup()) { |
// FIXME: We don't account for direction on columns and column groups. |
const BorderValue& column_adjoining_border = column->Style()->BorderEnd(); |
if (column_adjoining_border.Style() == EBorderStyle::kHidden) |
@@ -1511,11 +1517,8 @@ LayoutTableCell* LayoutTable::CellAbove(const LayoutTableCell* cell) const { |
} |
// Look up the cell in the section's grid, which requires effective col index |
- if (section) { |
- unsigned eff_col = |
- AbsoluteColumnToEffectiveColumn(cell->AbsoluteColumnIndex()); |
- return section->PrimaryCellAt(r_above, eff_col); |
- } |
+ if (section) |
+ return section->PrimaryCellAt(r_above, cell->EffectiveColumnIndex()); |
return nullptr; |
} |
@@ -1537,33 +1540,27 @@ LayoutTableCell* LayoutTable::CellBelow(const LayoutTableCell* cell) const { |
} |
// Look up the cell in the section's grid, which requires effective col index |
- if (section) { |
- unsigned eff_col = |
- AbsoluteColumnToEffectiveColumn(cell->AbsoluteColumnIndex()); |
- return section->PrimaryCellAt(r_below, eff_col); |
- } |
+ if (section) |
+ return section->PrimaryCellAt(r_below, cell->EffectiveColumnIndex()); |
return nullptr; |
} |
LayoutTableCell* LayoutTable::CellBefore(const LayoutTableCell* cell) const { |
RecalcSectionsIfNeeded(); |
- LayoutTableSection* section = cell->Section(); |
- unsigned eff_col = |
- AbsoluteColumnToEffectiveColumn(cell->AbsoluteColumnIndex()); |
+ unsigned eff_col = cell->EffectiveColumnIndex(); |
if (!eff_col) |
return nullptr; |
// If we hit a colspan back up to a real cell. |
- return section->PrimaryCellAt(cell->RowIndex(), eff_col - 1); |
+ return cell->Section()->PrimaryCellAt(cell->RowIndex(), eff_col - 1); |
} |
LayoutTableCell* LayoutTable::CellAfter(const LayoutTableCell* cell) const { |
RecalcSectionsIfNeeded(); |
- unsigned eff_col = AbsoluteColumnToEffectiveColumn( |
- cell->AbsoluteColumnIndex() + cell->ColSpan()); |
- return cell->Section()->PrimaryCellAt(cell->RowIndex(), eff_col); |
+ return cell->Section()->PrimaryCellAt( |
+ cell->RowIndex(), cell->EffectiveColumnIndexOfCellAfter()); |
} |
int LayoutTable::BaselinePosition(FontBaseline baseline_type, |