Bug 1395312 part 2. Table backgrounds should be drawn or not based on the visibility of the relevant cell, not of the column/row/colgroup/rowgroup they come from. r=heycam

MozReview-Commit-ID: B863KFWjLLW
This commit is contained in:
Boris Zbarsky
2017-08-31 09:12:35 -04:00
parent 6b35f48690
commit ad1763d800
8 changed files with 141 additions and 68 deletions

View File

@@ -0,0 +1,12 @@
<!DOCTYPE html>
<table style="width: 200px; height: 200px; empty-cells: hide; color: white">
<colgroup style="background: red">
<col style="background: red">
</colgroup>
<tbody style="background: red">
<tr style="background: red">
<td></td>
<td style="visibility: hidden">X</td>
</tr>
</tbody>
</table>

View File

@@ -0,0 +1,12 @@
<!DOCTYPE html>
<table style="width: 200px; height: 200px; empty-cells: show; color: white">
<colgroup style="background: red">
<col style="background: red">
</colgroup>
<tbody style="background: red">
<tr style="background: red">
<td style="background: white"></td>
<td style="visibility: hidden"></td>
</tr>
</tbody>
</table>

View File

@@ -0,0 +1,14 @@
<!DOCTYPE html>
<table style="width: 200px; height: 200px; empty-cells: show; border-collapse: collapse">
<colgroup style="background: red">
<col style="background: red">
</colgroup>
<tbody style="background: red">
<tr style="background: red">
<td style="background: green">
</td>
<td style="background: white">
</td>
</tr>
</tbody>
</table>

View File

@@ -0,0 +1,14 @@
<!DOCTYPE html>
<table style="width: 200px; height: 200px; empty-cells: hide; border-collapse: collapse">
<colgroup style="background: red">
<col style="background: red">
</colgroup>
<tbody style="background: red">
<tr style="background: green; visibility: hidden">
<td style="visibility: visible">
</td>
<td>
</td>
</tr>
</tbody>
</table>

View File

@@ -60,3 +60,7 @@ fuzzy-if(d2d||skiaContent,1,95000) == border-separate-opacity-table.html border-
== empty-cells-default-2.html empty-cells-default-2-ref.html == empty-cells-default-2.html empty-cells-default-2-ref.html
fuzzy-if(OSX,1,113) fuzzy-if(winWidget,1,12) fuzzy-if(winWidget&&!layersGPUAccelerated,82,116) fuzzy-if(skiaContent,84,5500) fuzzy-if(Android,2,5957) == table-row-opacity-dynamic-1.html table-row-opacity-dynamic-1-ref.html fuzzy-if(OSX,1,113) fuzzy-if(winWidget,1,12) fuzzy-if(winWidget&&!layersGPUAccelerated,82,116) fuzzy-if(skiaContent,84,5500) fuzzy-if(Android,2,5957) == table-row-opacity-dynamic-1.html table-row-opacity-dynamic-1-ref.html
== table-row-opacity-dynamic-2.html table-row-opacity-dynamic-2-ref.html == table-row-opacity-dynamic-2.html table-row-opacity-dynamic-2-ref.html
== hidden-cells-1.html about:blank
== hidden-cells-2.html about:blank
== hidden-cells-3.html hidden-cells-3-ref.html

View File

@@ -491,6 +491,12 @@ nsTableCellFrame::ShouldPaintBordersAndBackgrounds() const
return StyleTableBorder()->mEmptyCells == NS_STYLE_TABLE_EMPTY_CELLS_SHOW; return StyleTableBorder()->mEmptyCells == NS_STYLE_TABLE_EMPTY_CELLS_SHOW;
} }
bool
nsTableCellFrame::ShouldPaintBackground(nsDisplayListBuilder* aBuilder)
{
return ShouldPaintBordersAndBackgrounds() && IsVisibleInSelection(aBuilder);
}
void void
nsTableCellFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, nsTableCellFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists) const nsDisplayListSet& aLists)

View File

@@ -226,6 +226,8 @@ public:
bool ShouldPaintBordersAndBackgrounds() const; bool ShouldPaintBordersAndBackgrounds() const;
bool ShouldPaintBackground(nsDisplayListBuilder* aBuilder);
protected: protected:
nsTableCellFrame(nsStyleContext* aContext, nsTableFrame* aTableFrame, nsTableCellFrame(nsStyleContext* aContext, nsTableFrame* aTableFrame,
ClassID aID); ClassID aID);

View File

@@ -1377,6 +1377,10 @@ PaintRowBackground(nsTableRowFrame* aRow,
{ {
// Compute background rect by iterating all cell frame. // Compute background rect by iterating all cell frame.
for (nsTableCellFrame* cell = aRow->GetFirstCell(); cell; cell = cell->GetNextCell()) { for (nsTableCellFrame* cell = aRow->GetFirstCell(); cell; cell = cell->GetNextCell()) {
if (!cell->ShouldPaintBackground(aBuilder)) {
continue;
}
auto cellRect = cell->GetRectRelativeToSelf() + cell->GetNormalPosition() + aOffset; auto cellRect = cell->GetRectRelativeToSelf() + cell->GetNormalPosition() + aOffset;
if (!aBuilder->GetDirtyRect().Intersects(cellRect)) { if (!aBuilder->GetDirtyRect().Intersects(cellRect)) {
continue; continue;
@@ -1418,6 +1422,10 @@ PaintRowGroupBackgroundByColIdx(nsTableRowGroupFrame* aRowGroup,
continue; continue;
} }
for (nsTableCellFrame* cell = row->GetFirstCell(); cell; cell = cell->GetNextCell()) { for (nsTableCellFrame* cell = row->GetFirstCell(); cell; cell = cell->GetNextCell()) {
if (!cell->ShouldPaintBackground(aBuilder)) {
continue;
}
int32_t curColIdx; int32_t curColIdx;
cell->GetColIndex(curColIdx); cell->GetColIndex(curColIdx);
if (aColIdx.Contains(curColIdx)) { if (aColIdx.Contains(curColIdx)) {
@@ -1511,89 +1519,90 @@ nsTableFrame::DisplayGenericTablePart(nsDisplayListBuilder* aBuilder,
DisplayGenericTablePartTraversal aTraversal) DisplayGenericTablePartTraversal aTraversal)
{ {
bool isVisible = aFrame->IsVisibleForPainting(aBuilder); bool isVisible = aFrame->IsVisibleForPainting(aBuilder);
bool isColumn = aFrame->IsTableColFrame(); bool isTable = aFrame->IsTableFrame();
// If we have an anonymous column in the AppendAnonymousColFrames sense, it
// might think it's visible for painting (due to not inheriting its colgroup's // Note that we UpdateForFrameBackground() even if we're not visible, unless
// styles) while the colgroup as a whole is actually not visible for painting // we're a table frame, because our backgrounds may paint anyway if the _cell_
// because it has hidden visibility. In that situation we should also treat // is visible.
// the column as not visible, because otherwise hit-testing can get a bit if (isVisible || !isTable) {
// confused.
//
// XXXbz It's not clear whether anonymous columns and column groups should
// ever affect hit-testing at all. See
// https://github.com/w3c/csswg-drafts/issues/1763 which might result in them
// not existing conceptually and hence not affecting hit-testing.
if (isVisible && isColumn &&
aFrame->StyleContext()->GetPseudo() == nsCSSAnonBoxes::tableCol &&
!aFrame->GetParent()->StyleVisibility()->IsVisible()) {
isVisible = false;
}
if (isVisible) {
nsDisplayTableItem* currentItem = aBuilder->GetCurrentTableItem(); nsDisplayTableItem* currentItem = aBuilder->GetCurrentTableItem();
// currentItem may be null, when none of the table parts have a // currentItem may be null, when none of the table parts have a
// background or border // background or border
if (currentItem) { if (currentItem) {
currentItem->UpdateForFrameBackground(aFrame); currentItem->UpdateForFrameBackground(aFrame);
} }
}
if (isVisible) {
// XXXbz should box-shadow for rows/rowgroups/columns/colgroups get painted
// just because we're visible? Or should it depend on the cell visibility
// when we're not the whole table?
// Paint the outset box-shadows for the table frames // Paint the outset box-shadows for the table frames
bool hasBoxShadow = aFrame->StyleEffects()->mBoxShadow != nullptr; if (aFrame->StyleEffects()->mBoxShadow) {
if (hasBoxShadow) {
aLists.BorderBackground()->AppendNewToTop( aLists.BorderBackground()->AppendNewToTop(
new (aBuilder) nsDisplayBoxShadowOuter(aBuilder, aFrame)); new (aBuilder) nsDisplayBoxShadowOuter(aBuilder, aFrame));
} }
}
if (aFrame->IsTableRowGroupFrame()) { // Background visibility for rows, rowgroups, columns, colgroups depends on
nsTableRowGroupFrame* rowGroup = static_cast<nsTableRowGroupFrame*>(aFrame); // the visibility of the _cell_, not of the row/col(group).
PaintRowGroupBackground(rowGroup, aFrame, aBuilder, aLists); if (aFrame->IsTableRowGroupFrame()) {
} else if (aFrame->IsTableRowFrame()) { nsTableRowGroupFrame* rowGroup = static_cast<nsTableRowGroupFrame*>(aFrame);
nsTableRowFrame* row = static_cast<nsTableRowFrame*>(aFrame); PaintRowGroupBackground(rowGroup, aFrame, aBuilder, aLists);
PaintRowBackground(row, aFrame, aBuilder, aLists); } else if (aFrame->IsTableRowFrame()) {
} else if (aFrame->IsTableColGroupFrame()) { nsTableRowFrame* row = static_cast<nsTableRowFrame*>(aFrame);
// Compute background rect by iterating all cell frame. PaintRowBackground(row, aFrame, aBuilder, aLists);
nsTableColGroupFrame* colGroup = static_cast<nsTableColGroupFrame*>(aFrame); } else if (aFrame->IsTableColGroupFrame()) {
// Collecting column index. // Compute background rect by iterating all cell frame.
AutoTArray<int32_t, 1> colIdx; nsTableColGroupFrame* colGroup = static_cast<nsTableColGroupFrame*>(aFrame);
for (nsTableColFrame* col = colGroup->GetFirstColumn(); col; col = col->GetNextCol()) { // Collecting column index.
colIdx.AppendElement(col->GetColIndex()); AutoTArray<int32_t, 1> colIdx;
} for (nsTableColFrame* col = colGroup->GetFirstColumn(); col; col = col->GetNextCol()) {
nsTableFrame* table = colGroup->GetTableFrame();
RowGroupArray rowGroups;
table->OrderRowGroups(rowGroups);
for (nsTableRowGroupFrame* rowGroup : rowGroups) {
auto offset = rowGroup->GetNormalPosition() - colGroup->GetNormalPosition();
if (!aBuilder->GetDirtyRect().Intersects(nsRect(offset, rowGroup->GetSize()))) {
continue;
}
PaintRowGroupBackgroundByColIdx(rowGroup, aFrame, aBuilder, aLists, colIdx, offset);
}
} else if (isColumn) {
// Compute background rect by iterating all cell frame.
nsTableColFrame* col = static_cast<nsTableColFrame*>(aFrame);
AutoTArray<int32_t, 1> colIdx;
colIdx.AppendElement(col->GetColIndex()); colIdx.AppendElement(col->GetColIndex());
nsTableFrame* table = col->GetTableFrame();
RowGroupArray rowGroups;
table->OrderRowGroups(rowGroups);
for (nsTableRowGroupFrame* rowGroup : rowGroups) {
auto offset = rowGroup->GetNormalPosition() -
col->GetNormalPosition() -
col->GetTableColGroupFrame()->GetNormalPosition();
if (!aBuilder->GetDirtyRect().Intersects(nsRect(offset, rowGroup->GetSize()))) {
continue;
}
PaintRowGroupBackgroundByColIdx(rowGroup, aFrame, aBuilder, aLists, colIdx, offset);
}
} else {
nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, aFrame,
aFrame->GetRectRelativeToSelf(),
aLists.BorderBackground());
} }
nsTableFrame* table = colGroup->GetTableFrame();
RowGroupArray rowGroups;
table->OrderRowGroups(rowGroups);
for (nsTableRowGroupFrame* rowGroup : rowGroups) {
auto offset = rowGroup->GetNormalPosition() - colGroup->GetNormalPosition();
if (!aBuilder->GetDirtyRect().Intersects(nsRect(offset, rowGroup->GetSize()))) {
continue;
}
PaintRowGroupBackgroundByColIdx(rowGroup, aFrame, aBuilder, aLists, colIdx, offset);
}
} else if (aFrame->IsTableColFrame()) {
// Compute background rect by iterating all cell frame.
nsTableColFrame* col = static_cast<nsTableColFrame*>(aFrame);
AutoTArray<int32_t, 1> colIdx;
colIdx.AppendElement(col->GetColIndex());
nsTableFrame* table = col->GetTableFrame();
RowGroupArray rowGroups;
table->OrderRowGroups(rowGroups);
for (nsTableRowGroupFrame* rowGroup : rowGroups) {
auto offset = rowGroup->GetNormalPosition() -
col->GetNormalPosition() -
col->GetTableColGroupFrame()->GetNormalPosition();
if (!aBuilder->GetDirtyRect().Intersects(nsRect(offset, rowGroup->GetSize()))) {
continue;
}
PaintRowGroupBackgroundByColIdx(rowGroup, aFrame, aBuilder, aLists, colIdx, offset);
}
} else if (isVisible) {
nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, aFrame,
aFrame->GetRectRelativeToSelf(),
aLists.BorderBackground());
}
if (isVisible) {
// XXXbz should box-shadow for rows/rowgroups/columns/colgroups get painted
// just because we're visible? Or should it depend on the cell visibility
// when we're not the whole table?
// Paint the inset box-shadows for the table frames // Paint the inset box-shadows for the table frames
if (hasBoxShadow) { if (aFrame->StyleEffects()->mBoxShadow) {
aLists.BorderBackground()->AppendNewToTop( aLists.BorderBackground()->AppendNewToTop(
new (aBuilder) nsDisplayBoxShadowInner(aBuilder, aFrame)); new (aBuilder) nsDisplayBoxShadowInner(aBuilder, aFrame));
} }
@@ -1602,7 +1611,7 @@ nsTableFrame::DisplayGenericTablePart(nsDisplayListBuilder* aBuilder,
aTraversal(aBuilder, aFrame, aLists); aTraversal(aBuilder, aFrame, aLists);
if (isVisible) { if (isVisible) {
if (aFrame->IsTableFrame()) { if (isTable) {
nsTableFrame* table = static_cast<nsTableFrame*>(aFrame); nsTableFrame* table = static_cast<nsTableFrame*>(aFrame);
// In the collapsed border model, overlay all collapsed borders. // In the collapsed border model, overlay all collapsed borders.
if (table->IsBorderCollapse()) { if (table->IsBorderCollapse()) {