| 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,
|
|
|