Commit ed672497 authored by Xianzhu Wang's avatar Xianzhu Wang Committed by Commit Bot

Improve LayoutTable outer collapsed border calculation

Remove code in LayoutTable and LayoutTableSection for computing outer
borders. Use cells' cached collapsed borders instead.

This is mostly a pure refactoring, except it affects some corner cases:
- Previously collapsed borders for colgroup were not included in table's
  border. See changes to results of
  paint/invalidation/table/cached-change-border-color.html.
- Previously when the row and the table were in different inline
  direction and the the width of some collapsed border was in odd
  number, the distribution of the 1 pixel into half outer and inner
  borders was inconsistent. Now we always give the 1 pixel in the
  same way defined in LayoutTableCell::CollapsedBOrderHalfXXX().
  See changes to results of fast/table/border-collapsing/002.html.

Change-Id: I74e6d9173e5d46933fa7456cb713c370e9e7d464
Reviewed-on: https://chromium-review.googlesource.com/515606
Commit-Queue: Xianzhu Wang <wangxianzhu@chromium.org>
Reviewed-by: default avatarDavid Grogan <dgrogan@chromium.org>
Reviewed-by: default avatarWalter Korman <wkorman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#476219}
parent 3ac5e57d
......@@ -8,7 +8,7 @@
"paintInvalidations": [
{
"object": "LayoutTableCol COLGROUP id='colgroup'",
"rect": [8, 8, 166, 102],
"rect": [8, 8, 167, 104],
"reason": "style change"
}
]
......
......@@ -6,44 +6,54 @@
"contentsOpaque": true,
"drawsContent": true,
"paintInvalidations": [
{
"object": "LayoutTableCol COLGROUP id='colgroup'",
"rect": [8, 8, 167, 104],
"reason": "style change"
},
{
"object": "LayoutTableSection TBODY",
"rect": [7, 7, 167, 104],
"rect": [8, 8, 167, 104],
"reason": "geometry"
},
{
"object": "LayoutTableCol COLGROUP id='colgroup'",
"rect": [8, 8, 166, 102],
"reason": "style change"
"object": "LayoutTable TABLE",
"rect": [8, 108, 167, 4],
"reason": "incremental"
},
{
"object": "LayoutTableCell TD",
"rect": [64, 8, 58, 53],
"reason": "geometry"
},
{
"object": "LayoutTableCell TD",
"rect": [63, 7, 58, 53],
"rect": [8, 59, 58, 53],
"reason": "geometry"
},
{
"object": "LayoutTableCell TD",
"rect": [7, 58, 58, 53],
"rect": [8, 8, 58, 53],
"reason": "geometry"
},
{
"object": "LayoutTableCell TD",
"rect": [7, 7, 58, 53],
"rect": [118, 60, 57, 52],
"reason": "geometry"
},
{
"object": "LayoutTableCell TD",
"rect": [117, 59, 57, 52],
"rect": [118, 8, 57, 52],
"reason": "geometry"
},
{
"object": "LayoutTableCell TD",
"rect": [117, 7, 57, 52],
"rect": [65, 60, 57, 52],
"reason": "geometry"
},
{
"object": "LayoutTableCell TD",
"rect": [64, 59, 57, 52],
"rect": [8, 58, 56, 52],
"reason": "geometry"
},
{
......@@ -68,7 +78,7 @@
},
{
"object": "LayoutTable TABLE",
"rect": [169, 8, 5, 102],
"rect": [169, 8, 6, 104],
"reason": "incremental"
}
]
......@@ -111,6 +121,10 @@
"object": "LayoutTableSection TBODY",
"reason": "geometry"
},
{
"object": "LayoutTableRow TR",
"reason": "geometry"
},
{
"object": "LayoutTableCell TD",
"reason": "geometry"
......@@ -123,6 +137,10 @@
"object": "LayoutTableCell TD",
"reason": "geometry"
},
{
"object": "LayoutTableRow TR",
"reason": "geometry"
},
{
"object": "LayoutTableCell TD",
"reason": "geometry"
......
layer at (0,0) size 800x600 scrollWidth 970
layer at (0,0) size 800x600 scrollWidth 971
LayoutView at (0,0) size 800x600
layer at (0,0) size 800x600
LayoutBlockFlow {HTML} at (0,0) size 800x600
......
layer at (0,0) size 800x600 scrollWidth 1070
layer at (0,0) size 800x600 scrollWidth 1071
LayoutView at (0,0) size 800x600
layer at (0,0) size 800x600
LayoutBlockFlow {HTML} at (0,0) size 800x600
......
layer at (0,0) size 800x600 scrollWidth 1066
layer at (0,0) size 800x600 scrollWidth 1067
LayoutView at (0,0) size 800x600
layer at (0,0) size 800x600
LayoutBlockFlow {HTML} at (0,0) size 800x600
......
......@@ -1315,6 +1315,7 @@ source_set("unit_tests") {
"layout/LayoutTableCellTest.cpp",
"layout/LayoutTableRowTest.cpp",
"layout/LayoutTableSectionTest.cpp",
"layout/LayoutTableTest.cpp",
"layout/LayoutTestHelper.cpp",
"layout/LayoutTestHelper.h",
"layout/LayoutTextTest.cpp",
......
......@@ -149,8 +149,8 @@ class CORE_EXPORT LayoutTable final : public LayoutBlock {
return Style()->BorderCollapse() == EBorderCollapse::kCollapse;
}
LayoutUnit BorderStart() const override { return LayoutUnit(border_start_); }
LayoutUnit BorderEnd() const override { return LayoutUnit(border_end_); }
LayoutUnit BorderStart() const override;
LayoutUnit BorderEnd() const override;
LayoutUnit BorderBefore() const override;
LayoutUnit BorderAfter() const override;
......@@ -182,47 +182,6 @@ class CORE_EXPORT LayoutTable final : public LayoutBlock {
return Style()->IsLeftToRightDirection() ? BorderEnd() : BorderStart();
}
int OuterBorderBefore() const;
int OuterBorderAfter() const;
int OuterBorderStart() const;
int OuterBorderEnd() const;
int OuterBorderLeft() const {
if (Style()->IsHorizontalWritingMode())
return Style()->IsLeftToRightDirection() ? OuterBorderStart()
: OuterBorderEnd();
return Style()->IsFlippedBlocksWritingMode() ? OuterBorderAfter()
: OuterBorderBefore();
}
int OuterBorderRight() const {
if (Style()->IsHorizontalWritingMode())
return Style()->IsLeftToRightDirection() ? OuterBorderEnd()
: OuterBorderStart();
return Style()->IsFlippedBlocksWritingMode() ? OuterBorderBefore()
: OuterBorderAfter();
}
int OuterBorderTop() const {
if (Style()->IsHorizontalWritingMode())
return Style()->IsFlippedBlocksWritingMode() ? OuterBorderAfter()
: OuterBorderBefore();
return Style()->IsLeftToRightDirection() ? OuterBorderStart()
: OuterBorderEnd();
}
int OuterBorderBottom() const {
if (Style()->IsHorizontalWritingMode())
return Style()->IsFlippedBlocksWritingMode() ? OuterBorderBefore()
: OuterBorderAfter();
return Style()->IsLeftToRightDirection() ? OuterBorderEnd()
: OuterBorderStart();
}
int CalcBorderStart() const;
int CalcBorderEnd() const;
void RecalcBordersInRowDirection();
void AddChild(LayoutObject* child,
LayoutObject* before_child = nullptr) override;
......@@ -274,12 +233,13 @@ class CORE_EXPORT LayoutTable final : public LayoutBlock {
return row_offset_from_repeating_header_;
}
// This function returns 0 if the table has no section.
// These functions return nullptr if the table has no sections.
LayoutTableSection* TopSection() const;
LayoutTableSection* BottomSection() const;
// This function returns 0 if the table has no non-empty sections.
// These functions return nullptr if the table has no non-empty sections.
LayoutTableSection* TopNonEmptySection() const;
LayoutTableSection* BottomNonEmptySection() const;
unsigned LastEffectiveColumnIndex() const {
return NumEffectiveColumns() - 1;
......@@ -522,6 +482,13 @@ class CORE_EXPORT LayoutTable final : public LayoutBlock {
void AddOverflowFromChildren() override;
void RecalcSections() const;
void UpdateCollapsedOuterBorders() const;
unsigned ComputeCollapsedOuterBorderBefore() const;
unsigned ComputeCollapsedOuterBorderAfter() const;
unsigned ComputeCollapsedOuterBorderStart() const;
unsigned ComputeCollapsedOuterBorderEnd() const;
void LayoutCaption(LayoutTableCaption&, SubtreeLayoutScope&);
void LayoutSection(LayoutTableSection&,
SubtreeLayoutScope&,
......@@ -589,6 +556,7 @@ class CORE_EXPORT LayoutTable final : public LayoutBlock {
CollapsedBorderValues collapsed_borders_;
bool collapsed_borders_valid_ : 1;
bool needs_invalidate_collapsed_borders_for_all_cells_ : 1;
mutable bool collapsed_outer_borders_valid_ : 1;
mutable bool has_col_elements_ : 1;
mutable bool needs_section_recalc_ : 1;
......@@ -606,8 +574,11 @@ class CORE_EXPORT LayoutTable final : public LayoutBlock {
short h_spacing_;
short v_spacing_;
int border_start_;
int border_end_;
mutable unsigned collapsed_outer_border_start_;
mutable unsigned collapsed_outer_border_end_;
mutable unsigned collapsed_outer_border_before_;
mutable unsigned collapsed_outer_border_after_;
LayoutUnit block_offset_to_first_repeatable_header_;
LayoutUnit row_offset_from_repeating_header_;
......
......@@ -433,10 +433,10 @@ void LayoutTableCell::ComputeOverflow(LayoutUnit old_client_after_edge,
// Our border rect already includes the inner halves of the collapsed borders,
// so here we get the outer halves.
bool rtl = !StyleForCellFlow().IsLeftToRightDirection();
LayoutUnit left = CollapsedBorderHalfLeft(true);
LayoutUnit right = CollapsedBorderHalfRight(true);
LayoutUnit top = CollapsedBorderHalfTop(true);
LayoutUnit bottom = CollapsedBorderHalfBottom(true);
unsigned left = CollapsedBorderHalfLeft(true);
unsigned right = CollapsedBorderHalfRight(true);
unsigned top = CollapsedBorderHalfTop(true);
unsigned bottom = CollapsedBorderHalfBottom(true);
// This cell's borders may be lengthened to match the widths of orthogonal
// borders of adjacent cells. Expand visual overflow to cover the lengthened
......@@ -467,7 +467,8 @@ void LayoutTableCell::ComputeOverflow(LayoutUnit old_client_after_edge,
}
LayoutRect rect = BorderBoxRect();
rect.ExpandEdges(top, right, bottom, left);
rect.ExpandEdges(LayoutUnit(top), LayoutUnit(right), LayoutUnit(bottom),
LayoutUnit(left));
collapsed_border_values_->SetLocalVisualRect(rect);
}
......@@ -1136,49 +1137,57 @@ CollapsedBorderValue LayoutTableCell::ComputeCollapsedAfterBorder() const {
}
LayoutUnit LayoutTableCell::BorderLeft() const {
return Table()->ShouldCollapseBorders() ? CollapsedBorderHalfLeft(false)
: LayoutBlockFlow::BorderLeft();
return Table()->ShouldCollapseBorders()
? LayoutUnit(CollapsedBorderHalfLeft(false))
: LayoutBlockFlow::BorderLeft();
}
LayoutUnit LayoutTableCell::BorderRight() const {
return Table()->ShouldCollapseBorders() ? CollapsedBorderHalfRight(false)
: LayoutBlockFlow::BorderRight();
return Table()->ShouldCollapseBorders()
? LayoutUnit(CollapsedBorderHalfRight(false))
: LayoutBlockFlow::BorderRight();
}
LayoutUnit LayoutTableCell::BorderTop() const {
return Table()->ShouldCollapseBorders() ? CollapsedBorderHalfTop(false)
: LayoutBlockFlow::BorderTop();
return Table()->ShouldCollapseBorders()
? LayoutUnit(CollapsedBorderHalfTop(false))
: LayoutBlockFlow::BorderTop();
}
LayoutUnit LayoutTableCell::BorderBottom() const {
return Table()->ShouldCollapseBorders() ? CollapsedBorderHalfBottom(false)
: LayoutBlockFlow::BorderBottom();
return Table()->ShouldCollapseBorders()
? LayoutUnit(CollapsedBorderHalfBottom(false))
: LayoutBlockFlow::BorderBottom();
}
// FIXME: https://bugs.webkit.org/show_bug.cgi?id=46191, make the collapsed
// border drawing work with different block flow values instead of being
// hard-coded to top-to-bottom.
LayoutUnit LayoutTableCell::BorderStart() const {
return Table()->ShouldCollapseBorders() ? CollapsedBorderHalfStart(false)
: LayoutBlockFlow::BorderStart();
return Table()->ShouldCollapseBorders()
? LayoutUnit(CollapsedBorderHalfStart(false))
: LayoutBlockFlow::BorderStart();
}
LayoutUnit LayoutTableCell::BorderEnd() const {
return Table()->ShouldCollapseBorders() ? CollapsedBorderHalfEnd(false)
: LayoutBlockFlow::BorderEnd();
return Table()->ShouldCollapseBorders()
? LayoutUnit(CollapsedBorderHalfEnd(false))
: LayoutBlockFlow::BorderEnd();
}
LayoutUnit LayoutTableCell::BorderBefore() const {
return Table()->ShouldCollapseBorders() ? CollapsedBorderHalfBefore(false)
: LayoutBlockFlow::BorderBefore();
return Table()->ShouldCollapseBorders()
? LayoutUnit(CollapsedBorderHalfBefore(false))
: LayoutBlockFlow::BorderBefore();
}
LayoutUnit LayoutTableCell::BorderAfter() const {
return Table()->ShouldCollapseBorders() ? CollapsedBorderHalfAfter(false)
: LayoutBlockFlow::BorderAfter();
return Table()->ShouldCollapseBorders()
? LayoutUnit(CollapsedBorderHalfAfter(false))
: LayoutBlockFlow::BorderAfter();
}
LayoutUnit LayoutTableCell::CollapsedBorderHalfLeft(bool outer) const {
unsigned LayoutTableCell::CollapsedBorderHalfLeft(bool outer) const {
const ComputedStyle& style_for_cell_flow = this->StyleForCellFlow();
if (style_for_cell_flow.IsHorizontalWritingMode()) {
return style_for_cell_flow.IsLeftToRightDirection()
......@@ -1190,7 +1199,7 @@ LayoutUnit LayoutTableCell::CollapsedBorderHalfLeft(bool outer) const {
: CollapsedBorderHalfBefore(outer);
}
LayoutUnit LayoutTableCell::CollapsedBorderHalfRight(bool outer) const {
unsigned LayoutTableCell::CollapsedBorderHalfRight(bool outer) const {
const ComputedStyle& style_for_cell_flow = this->StyleForCellFlow();
if (style_for_cell_flow.IsHorizontalWritingMode()) {
return style_for_cell_flow.IsLeftToRightDirection()
......@@ -1202,7 +1211,7 @@ LayoutUnit LayoutTableCell::CollapsedBorderHalfRight(bool outer) const {
: CollapsedBorderHalfAfter(outer);
}
LayoutUnit LayoutTableCell::CollapsedBorderHalfTop(bool outer) const {
unsigned LayoutTableCell::CollapsedBorderHalfTop(bool outer) const {
const ComputedStyle& style_for_cell_flow = this->StyleForCellFlow();
if (style_for_cell_flow.IsHorizontalWritingMode()) {
return style_for_cell_flow.IsFlippedBlocksWritingMode()
......@@ -1214,7 +1223,7 @@ LayoutUnit LayoutTableCell::CollapsedBorderHalfTop(bool outer) const {
: CollapsedBorderHalfEnd(outer);
}
LayoutUnit LayoutTableCell::CollapsedBorderHalfBottom(bool outer) const {
unsigned LayoutTableCell::CollapsedBorderHalfBottom(bool outer) const {
const ComputedStyle& style_for_cell_flow = this->StyleForCellFlow();
if (style_for_cell_flow.IsHorizontalWritingMode()) {
return style_for_cell_flow.IsFlippedBlocksWritingMode()
......@@ -1226,68 +1235,66 @@ LayoutUnit LayoutTableCell::CollapsedBorderHalfBottom(bool outer) const {
: CollapsedBorderHalfStart(outer);
}
LayoutUnit LayoutTableCell::CollapsedBorderHalfStart(bool outer) const {
unsigned LayoutTableCell::CollapsedBorderHalfStart(bool outer) const {
UpdateCollapsedBorderValues();
const auto* collapsed_border_values = this->GetCollapsedBorderValues();
if (!collapsed_border_values)
return LayoutUnit();
return 0;
const auto& border = collapsed_border_values->StartBorder();
if (border.Exists()) {
return LayoutUnit(
(border.Width() +
((StyleForCellFlow().IsLeftToRightDirection() ^ outer) ? 1 : 0)) /
2); // Give the extra pixel to top and left.
return (border.Width() +
((StyleForCellFlow().IsLeftToRightDirection() ^ outer) ? 1 : 0)) /
2; // Give the extra pixel to top and left.
}
return LayoutUnit();
return 0;
}
LayoutUnit LayoutTableCell::CollapsedBorderHalfEnd(bool outer) const {
unsigned LayoutTableCell::CollapsedBorderHalfEnd(bool outer) const {
UpdateCollapsedBorderValues();
const auto* collapsed_border_values = this->GetCollapsedBorderValues();
if (!collapsed_border_values)
return LayoutUnit();
return 0;
const auto& border = collapsed_border_values->EndBorder();
if (border.Exists()) {
return LayoutUnit(
(border.Width() +
((StyleForCellFlow().IsLeftToRightDirection() ^ outer) ? 0 : 1)) /
2);
return (border.Width() +
((StyleForCellFlow().IsLeftToRightDirection() ^ outer) ? 0 : 1)) /
2;
}
return LayoutUnit();
return 0;
}
LayoutUnit LayoutTableCell::CollapsedBorderHalfBefore(bool outer) const {
unsigned LayoutTableCell::CollapsedBorderHalfBefore(bool outer) const {
UpdateCollapsedBorderValues();
const auto* collapsed_border_values = this->GetCollapsedBorderValues();
if (!collapsed_border_values)
return LayoutUnit();
return 0;
const auto& border = collapsed_border_values->BeforeBorder();
if (border.Exists()) {
return LayoutUnit(
(border.Width() +
((StyleForCellFlow().IsFlippedBlocksWritingMode() ^ outer) ? 0 : 1)) /
2); // Give the extra pixel to top and left.
return (border.Width() +
((StyleForCellFlow().IsFlippedBlocksWritingMode() ^ outer) ? 0
: 1)) /
2; // Give the extra pixel to top and left.
}
return LayoutUnit();
return 0;
}
LayoutUnit LayoutTableCell::CollapsedBorderHalfAfter(bool outer) const {
unsigned LayoutTableCell::CollapsedBorderHalfAfter(bool outer) const {
UpdateCollapsedBorderValues();
const auto* collapsed_border_values = this->GetCollapsedBorderValues();
if (!collapsed_border_values)
return LayoutUnit();
return 0;
const auto& border = collapsed_border_values->AfterBorder();
if (border.Exists()) {
return LayoutUnit(
(border.Width() +
((StyleForCellFlow().IsFlippedBlocksWritingMode() ^ outer) ? 1 : 0)) /
2);
return (border.Width() +
((StyleForCellFlow().IsFlippedBlocksWritingMode() ^ outer) ? 1
: 0)) /
2;
}
return LayoutUnit();
return 0;
}
void LayoutTableCell::Paint(const PaintInfo& paint_info,
......
......@@ -355,6 +355,20 @@ class CORE_EXPORT LayoutTableCell final : public LayoutBlockFlow {
return cell1->RowIndex() < cell2->RowIndex();
}
// For LayoutTable to compute its collapsed outer borders.
unsigned CollapsedOuterBorderBefore() const {
return CollapsedBorderHalfBefore(true);
}
unsigned CollapsedOuterBorderAfter() const {
return CollapsedBorderHalfAfter(true);
}
unsigned CollapsedOuterBorderStart() const {
return CollapsedBorderHalfStart(true);
}
unsigned CollapsedOuterBorderEnd() const {
return CollapsedBorderHalfEnd(true);
}
protected:
void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
void ComputePreferredLogicalWidths() override;
......@@ -388,15 +402,15 @@ class CORE_EXPORT LayoutTableCell final : public LayoutBlockFlow {
bool recompute_floats = false) override;
LayoutRect LocalVisualRect() const override;
LayoutUnit CollapsedBorderHalfLeft(bool outer) const;
LayoutUnit CollapsedBorderHalfRight(bool outer) const;
LayoutUnit CollapsedBorderHalfTop(bool outer) const;
LayoutUnit CollapsedBorderHalfBottom(bool outer) const;
unsigned CollapsedBorderHalfLeft(bool outer) const;
unsigned CollapsedBorderHalfRight(bool outer) const;
unsigned CollapsedBorderHalfTop(bool outer) const;
unsigned CollapsedBorderHalfBottom(bool outer) const;
LayoutUnit CollapsedBorderHalfStart(bool outer) const;
LayoutUnit CollapsedBorderHalfEnd(bool outer) const;
LayoutUnit CollapsedBorderHalfBefore(bool outer) const;
LayoutUnit CollapsedBorderHalfAfter(bool outer) const;
unsigned CollapsedBorderHalfStart(bool outer) const;
unsigned CollapsedBorderHalfEnd(bool outer) const;
unsigned CollapsedBorderHalfBefore(bool outer) const;
unsigned CollapsedBorderHalfAfter(bool outer) const;
void SetIntrinsicPaddingBefore(int p) { intrinsic_padding_before_ = p; }
void SetIntrinsicPaddingAfter(int p) { intrinsic_padding_after_ = p; }
......
......@@ -90,10 +90,6 @@ LayoutTableSection::LayoutTableSection(Element* element)
: LayoutTableBoxComponent(element),
c_col_(0),
c_row_(0),
outer_border_start_(0),
outer_border_end_(0),
outer_border_before_(0),
outer_border_after_(0),
needs_cell_recalc_(false),
force_full_paint_(false),
has_multiple_cell_levels_(false),
......@@ -1354,174 +1350,6 @@ void LayoutTableSection::MarkAllCellsWidthsDirtyAndOrNeedsLayout(
}
}
int LayoutTableSection::CalcBlockDirectionOuterBorder(
BlockBorderSide side) const {
if (!grid_.size() || !Table()->NumEffectiveColumns())
return 0;
int border_width = 0;
EBorderStyle section_border_style = side == kBorderBefore
? Style()->BorderBeforeStyle()
: Style()->BorderAfterStyle();
if (section_border_style == EBorderStyle::kHidden)
return -1;
if (ComputedStyle::BorderStyleIsVisible(section_border_style)) {
border_width = side == kBorderBefore ? Style()->BorderBeforeWidth()
: Style()->BorderAfterWidth();
}
EBorderStyle row_border_style = side == kBorderBefore
? FirstRow()->Style()->BorderBeforeStyle()
: LastRow()->Style()->BorderAfterStyle();
float row_border_width = side == kBorderBefore
? FirstRow()->Style()->BorderBeforeWidth()
: LastRow()->Style()->BorderAfterWidth();
if (row_border_style == EBorderStyle::kHidden)
return -1;
if (ComputedStyle::BorderStyleIsVisible(row_border_style) &&
row_border_width > border_width)
border_width = row_border_width;
bool all_hidden = true;
unsigned r = side == kBorderBefore ? 0 : grid_.size() - 1;
unsigned n_cols = NumCols(r);
for (unsigned c = 0; c < n_cols; c++) {
const auto& grid_cell = GridCellAt(r, c);
if (grid_cell.InColSpan() || !grid_cell.HasCells())
continue;
const ComputedStyle& primary_cell_style =
grid_cell.PrimaryCell()->StyleRef();
// FIXME: Make this work with perpendicular and flipped cells.
EBorderStyle cell_border_style =
side == kBorderBefore ? primary_cell_style.BorderBeforeStyle()
: primary_cell_style.BorderAfterStyle();
float cell_border_width = side == kBorderBefore
? primary_cell_style.BorderBeforeWidth()
: primary_cell_style.BorderAfterWidth();
// FIXME: Don't repeat for the same col group
LayoutTableCol* col =
Table()->ColElementAtAbsoluteColumn(c).InnermostColOrColGroup();
if (col) {
EBorderStyle col_border_style = side == kBorderBefore
? col->Style()->BorderBeforeStyle()
: col->Style()->BorderAfterStyle();
const float col_border_width = side == kBorderBefore
? col->Style()->BorderBeforeWidth()
: col->Style()->BorderAfterWidth();
if (col_border_style == EBorderStyle::kHidden ||
cell_border_style == EBorderStyle::kHidden)
continue;
all_hidden = false;
if (ComputedStyle::BorderStyleIsVisible(col_border_style) &&
col_border_width > border_width)
border_width = col_border_width;
if (ComputedStyle::BorderStyleIsVisible(cell_border_style) &&
cell_border_width > border_width)
border_width = cell_border_width;
} else {
if (cell_border_style == EBorderStyle::kHidden)
continue;
all_hidden = false;
if (ComputedStyle::BorderStyleIsVisible(cell_border_style) &&
cell_border_width > border_width)
border_width = cell_border_width;
}
}
if (all_hidden)
return -1;
if (side == kBorderAfter)
border_width++; // Distribute rounding error
return border_width / 2;
}
int LayoutTableSection::CalcInlineDirectionOuterBorder(
InlineBorderSide side) const {
unsigned total_cols = Table()->NumEffectiveColumns();
if (!grid_.size() || !total_cols)
return 0;
unsigned col_index = side == kBorderStart ? 0 : total_cols - 1;
int border_width = 0;
EBorderStyle section_border_style = side == kBorderStart
? Style()->BorderStartStyle()
: Style()->BorderEndStyle();
const float section_border_width = side == kBorderStart
? Style()->BorderStartWidth()
: Style()->BorderEndWidth();
if (section_border_style == EBorderStyle::kHidden)
return -1;
if (ComputedStyle::BorderStyleIsVisible(section_border_style))
border_width = section_border_width;
if (LayoutTableCol* col = Table()
->ColElementAtAbsoluteColumn(col_index)
.InnermostColOrColGroup()) {
EBorderStyle col_border_style = side == kBorderStart
? col->Style()->BorderStartStyle()
: col->Style()->BorderEndStyle();
const float col_border_width = side == kBorderStart
? col->Style()->BorderStartWidth()
: col->Style()->BorderEndWidth();
if (col_border_style == EBorderStyle::kHidden)
return -1;
if (ComputedStyle::BorderStyleIsVisible(col_border_style) &&
col_border_width > border_width)
border_width = col_border_width;
}
bool all_hidden = true;
for (unsigned r = 0; r < grid_.size(); r++) {
if (col_index >= NumCols(r))
continue;
const auto& grid_cell = GridCellAt(r, col_index);
if (!grid_cell.HasCells())
continue;
// FIXME: Don't repeat for the same cell
const ComputedStyle& primary_cell_style =
grid_cell.PrimaryCell()->StyleRef();
const ComputedStyle& primary_cell_parent_style =
grid_cell.PrimaryCell()->Parent()->StyleRef();
// FIXME: Make this work with perpendicular and flipped cells.
EBorderStyle cell_border_style = side == kBorderStart
? primary_cell_style.BorderStartStyle()
: primary_cell_style.BorderEndStyle();
EBorderStyle row_border_style =
side == kBorderStart ? primary_cell_parent_style.BorderStartStyle()
: primary_cell_parent_style.BorderEndStyle();
const float cell_border_width = side == kBorderStart
? primary_cell_style.BorderStartWidth()
: primary_cell_style.BorderEndWidth();
const float row_border_width =
side == kBorderStart ? primary_cell_parent_style.BorderStartWidth()
: primary_cell_parent_style.BorderEndWidth();
if (cell_border_style == EBorderStyle::kHidden ||
row_border_style == EBorderStyle::kHidden)
continue;
all_hidden = false;
if (ComputedStyle::BorderStyleIsVisible(cell_border_style) &&
cell_border_width > border_width)
border_width = cell_border_width;
if (ComputedStyle::BorderStyleIsVisible(row_border_style) &&
row_border_width > border_width)
border_width = row_border_width;
}
if (all_hidden)
return -1;
if ((side == kBorderStart) != Table()->Style()->IsLeftToRightDirection())
border_width++; // Distribute rounding error
return border_width / 2;
}
void LayoutTableSection::RecalcOuterBorder() {
outer_border_before_ = CalcBlockDirectionOuterBorder(kBorderBefore);
outer_border_after_ = CalcBlockDirectionOuterBorder(kBorderAfter);
outer_border_start_ = CalcInlineDirectionOuterBorder(kBorderStart);
outer_border_end_ = CalcInlineDirectionOuterBorder(kBorderEnd);
}
int LayoutTableSection::FirstLineBoxBaseline() const {
if (!grid_.size())
return -1;
......
......@@ -204,17 +204,6 @@ class CORE_EXPORT LayoutTableSection final : public LayoutTableBoxComponent {
void AppendEffectiveColumn(unsigned pos);
void SplitEffectiveColumn(unsigned pos, unsigned first);
enum BlockBorderSide { kBorderBefore, kBorderAfter };
int CalcBlockDirectionOuterBorder(BlockBorderSide) const;
enum InlineBorderSide { kBorderStart, kBorderEnd };
int CalcInlineDirectionOuterBorder(InlineBorderSide) const;
void RecalcOuterBorder();
int OuterBorderBefore() const { return outer_border_before_; }
int OuterBorderAfter() const { return outer_border_after_; }
int OuterBorderStart() const { return outer_border_start_; }
int OuterBorderEnd() const { return outer_border_end_; }
unsigned NumRows() const {
DCHECK(!NeedsCellRecalc());
return grid_.size();
......@@ -439,11 +428,6 @@ class CORE_EXPORT LayoutTableSection final : public LayoutTableBoxComponent {
unsigned c_col_;
unsigned c_row_;
int outer_border_start_;
int outer_border_end_;
int outer_border_before_;
int outer_border_after_;
bool needs_cell_recalc_;
// This HashSet holds the overflowing cells for the partial paint path. If we
......
// Copyright 2017 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 "core/layout/LayoutTable.h"
#include "core/layout/LayoutTestHelper.h"
namespace blink {
namespace {
class LayoutTableTest : public RenderingTest {
protected:
LayoutTable* GetTableByElementId(const char* id) {
return ToLayoutTable(GetLayoutObjectByElementId(id));
}
};
TEST_F(LayoutTableTest, OverflowWithCollapsedBorders) {
SetBodyInnerHTML(
"<style>"
" table { border-collapse: collapse }"
" td { border: 0px solid blue; padding: 0 }"
" div { width: 100px; height: 100px }"
"</style>"
"<table id='table'>"
" <tr>"
" <td style='border-bottom-width: 10px;"
" outline: 3px solid blue'><div></div></td>"
" <td style='border-width: 3px 15px'><div></div></td>"
" </tr>"
" <tr style='outline: 8px solid green'><td><div></div></td></tr>"
"</table>");
auto* table = GetTableByElementId("table");
// The table's self visual overflow covers the collapsed borders.
EXPECT_EQ(LayoutRect(0, 0, 230, 211), table->BorderBoxRect());
EXPECT_EQ(LayoutRect(0, 0, 230, 211), table->SelfVisualOverflowRect());
// The table's visual overflow covers self visual overflow and content visual
// overflows.
LayoutRect expected_visual_overflow = table->ContentBoxRect();
expected_visual_overflow.ExpandEdges(LayoutUnit(3), LayoutUnit(8),
LayoutUnit(8), LayoutUnit(8));
EXPECT_EQ(expected_visual_overflow, table->VisualOverflowRect());
// Tables layout overflow equals visual overflow.
EXPECT_EQ(expected_visual_overflow, table->LayoutOverflowRect());
}
TEST_F(LayoutTableTest, CollapsedBorders) {
SetBodyInnerHTML(
"<style>table { border-collapse: collapse }</style>"
"<table id='table1'"
" style='border-top: hidden; border-bottom: 8px solid;"
" border-left: hidden; border-right: 10px solid'>"
" <tr><td>A</td><td>B</td></tr>"
"</table>"
"<table id='table2' style='border: 10px solid'>"
" <tr>"
" <td style='border: hidden'>C</td>"
" <td style='border: hidden'>D</td>"
" </tr>"
"</table>"
"<table id='table3' style='border: 10px solid'>"
" <tr>"
" <td style='border-top: 15px solid;"
" border-left: 21px solid'>E</td>"
" <td style='border-right: 25px solid'>F</td>"
" </tr>"
// The second row won't affect start and end borders of the table.
" <tr>"
" <td style='border: 30px solid'>G</td>"
" <td style='border: 40px solid'>H</td>"
" </tr>"
"</table>");
auto* table1 = GetTableByElementId("table1");
EXPECT_EQ(0, table1->BorderBefore());
EXPECT_EQ(4, table1->BorderAfter());
EXPECT_EQ(0, table1->BorderStart());
EXPECT_EQ(5, table1->BorderEnd());
// All cells have hidden border.
auto* table2 = GetTableByElementId("table2");
EXPECT_EQ(0, table2->BorderBefore());
EXPECT_EQ(0, table2->BorderAfter());
EXPECT_EQ(0, table2->BorderStart());
EXPECT_EQ(0, table2->BorderEnd());
// Cells have wider borders.
auto* table3 = GetTableByElementId("table3");
// Cell E's border-top won.
EXPECT_EQ(7, table3->BorderBefore());
// Cell H's border-bottom won.
EXPECT_EQ(20, table3->BorderAfter());
// Cell E's border-left won.
EXPECT_EQ(10, table3->BorderStart());
// Cell F's border-bottom won.
EXPECT_EQ(13, table3->BorderEnd());
}
TEST_F(LayoutTableTest, CollapsedBordersWithCol) {
SetBodyInnerHTML(
"<style>table { border-collapse: collapse }</style>"
"<table id='table1' style='border: hidden'>"
" <colgroup>"
" <col span='2000' style='border: 10px solid'>"
" <col span='2000' style='border: 20px solid'>"
" </colgroup>"
" <tr>"
" <td colspan='2000'>A</td>"
" <td colspan='2000'>B</td>"
" </tr>"
"</table>"
"<table id='table2' style='border: 10px solid'>"
" <colgroup>"
" <col span='2000' style='border: 10px solid'>"
" <col span='2000' style='border: 20px solid'>"
" </colgroup>"
" <tr>"
" <td colspan='2000' style='border: hidden'>C</td>"
" <td colspan='2000' style='border: hidden'>D</td>"
" </tr>"
"</table>"
"<table id='table3'>"
" <colgroup>"
" <col span='2000' style='border: 10px solid'>"
" <col span='2000' style='border: 20px solid'>"
" </colgroup>"
" <tr>"
" <td colspan='2000' style='border: 12px solid'>E</td>"
" <td colspan='2000' style='border: 16px solid'>F</td>"
" </tr>"
"</table>");
// Table has hidden border.
auto* table1 = GetTableByElementId("table1");
EXPECT_EQ(0, table1->BorderBefore());
EXPECT_EQ(0, table1->BorderAfter());
EXPECT_EQ(0, table1->BorderStart());
EXPECT_EQ(0, table1->BorderEnd());
// All cells have hidden border.
auto* table2 = GetTableByElementId("table2");
EXPECT_EQ(0, table2->BorderBefore());
EXPECT_EQ(0, table2->BorderAfter());
EXPECT_EQ(0, table2->BorderStart());
EXPECT_EQ(0, table2->BorderEnd());
// Combined cell and col borders.
auto* table3 = GetTableByElementId("table3");
// The second col's border-top won.
EXPECT_EQ(10, table3->BorderBefore());
// The second col's border-bottom won.
EXPECT_EQ(10, table3->BorderAfter());
// Cell E's border-left won.
EXPECT_EQ(6, table3->BorderStart());
// The second col's border-right won.
EXPECT_EQ(10, table3->BorderEnd());
}
} // anonymous namespace
} // namespace blink
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