blob: e675fd2bc157c9afe28450c9f157f322e4401e9b [file] [log] [blame]
// 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/layout_ng_table_section.h"
#include "third_party/blink/renderer/core/layout/layout_object_factory.h"
#include "third_party/blink/renderer/core/layout/ng/table/layout_ng_table.h"
#include "third_party/blink/renderer/core/layout/ng/table/layout_ng_table_row.h"
#include "third_party/blink/renderer/core/layout/ng/table/ng_table_borders.h"
namespace blink {
LayoutNGTableSection::LayoutNGTableSection(Element* element)
: LayoutNGMixin<LayoutBlock>(element) {}
bool LayoutNGTableSection::IsEmpty() const {
NOT_DESTROYED();
return !FirstChild();
}
LayoutNGTable* LayoutNGTableSection::Table() const {
NOT_DESTROYED();
return To<LayoutNGTable>(Parent());
}
void LayoutNGTableSection::AddChild(LayoutObject* child,
LayoutObject* before_child) {
NOT_DESTROYED();
if (LayoutNGTable* table = Table())
table->TableGridStructureChanged();
if (!child->IsTableRow()) {
LayoutObject* last = before_child;
if (!last)
last = LastChild();
if (last && last->IsAnonymous() && last->IsTablePart() &&
!last->IsBeforeOrAfterContent()) {
if (before_child == last)
before_child = last->SlowFirstChild();
last->AddChild(child, before_child);
return;
}
if (before_child && !before_child->IsAnonymous() &&
before_child->Parent() == this) {
LayoutObject* row = before_child->PreviousSibling();
if (row && row->IsTableRow() && row->IsAnonymous()) {
row->AddChild(child);
return;
}
}
// If before_child is inside an anonymous cell/row, insert into the cell or
// into the anonymous row containing it, if there is one.
LayoutObject* last_box = last;
while (last_box && last_box->Parent()->IsAnonymous() &&
!last_box->IsTableRow())
last_box = last_box->Parent();
if (last_box && last_box->IsAnonymous() &&
!last_box->IsBeforeOrAfterContent()) {
last_box->AddChild(child, before_child);
return;
}
LayoutObject* row =
LayoutObjectFactory::CreateAnonymousTableRowWithParent(*this);
AddChild(row, before_child);
row->AddChild(child);
return;
}
if (before_child && before_child->Parent() != this)
before_child = SplitAnonymousBoxesAroundChild(before_child);
LayoutNGMixin<LayoutBlock>::AddChild(child, before_child);
}
void LayoutNGTableSection::RemoveChild(LayoutObject* child) {
NOT_DESTROYED();
if (LayoutNGTable* table = Table())
table->TableGridStructureChanged();
LayoutNGMixin<LayoutBlock>::RemoveChild(child);
}
void LayoutNGTableSection::WillBeRemovedFromTree() {
NOT_DESTROYED();
if (LayoutNGTable* table = Table())
table->TableGridStructureChanged();
LayoutNGMixin<LayoutBlock>::WillBeRemovedFromTree();
}
void LayoutNGTableSection::StyleDidChange(StyleDifference diff,
const ComputedStyle* old_style) {
NOT_DESTROYED();
if (LayoutNGTable* table = Table()) {
if ((old_style && !old_style->BorderVisuallyEqual(StyleRef())) ||
(diff.TextDecorationOrColorChanged() &&
StyleRef().HasBorderColorReferencingCurrentColor())) {
table->GridBordersChanged();
}
}
LayoutNGMixin<LayoutBlock>::StyleDidChange(diff, old_style);
}
LayoutBox* LayoutNGTableSection::CreateAnonymousBoxWithSameTypeAs(
const LayoutObject* parent) const {
NOT_DESTROYED();
return LayoutObjectFactory::CreateAnonymousTableSectionWithParent(*parent);
}
LayoutNGTableInterface* LayoutNGTableSection::TableInterface() const {
NOT_DESTROYED();
return ToInterface<LayoutNGTableInterface>(Parent());
}
void LayoutNGTableSection::SetNeedsCellRecalc() {
NOT_DESTROYED();
SetNeedsLayout(layout_invalidation_reason::kDomChanged);
}
LayoutNGTableRowInterface* LayoutNGTableSection::FirstRowInterface() const {
NOT_DESTROYED();
return ToInterface<LayoutNGTableRowInterface>(FirstChild());
}
LayoutNGTableRowInterface* LayoutNGTableSection::LastRowInterface() const {
NOT_DESTROYED();
return ToInterface<LayoutNGTableRowInterface>(LastChild());
}
// TODO(crbug.com/1079133): Used by AXLayoutObject::IsDataTable, verify
// behaviour is correct. Consider removing these methods.
unsigned LayoutNGTableSection::NumEffectiveColumns() const {
NOT_DESTROYED();
const LayoutNGTable* table = Table();
DCHECK(table);
wtf_size_t column_count = table->ColumnCount();
if (column_count == 0)
return 0;
return table->AbsoluteColumnToEffectiveColumn(column_count - 1) + 1;
}
// TODO(crbug.com/1079133): Used by AXLayoutObject::IsDataTable/ColumnCount,
// verify behaviour is correct.
unsigned LayoutNGTableSection::NumCols(unsigned row) const {
NOT_DESTROYED();
unsigned current_row = 0;
for (LayoutObject* layout_row = FirstChild(); layout_row;
layout_row = layout_row->NextSibling()) {
if (current_row++ == row) {
unsigned current_column = 0;
for (LayoutObject* layout_cell = FirstChild(); layout_cell;
layout_cell = layout_cell->NextSibling()) {
++current_column;
}
return current_column;
}
}
return 0;
}
// TODO(crbug.com/1079133): Used by AXLayoutObject, verify behaviour is
// correct, and if caching is required.
unsigned LayoutNGTableSection::NumRows() const {
NOT_DESTROYED();
unsigned num_rows = 0;
for (LayoutObject* layout_row = FirstChild(); layout_row;
layout_row = layout_row->NextSibling()) {
// TODO(crbug.com/1079133) skip for abspos?
++num_rows;
}
return num_rows;
}
} // namespace blink