From fddc35e4384c20b1ad5d0c9818f490be29b1ece5 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sun, 2 Feb 2020 02:16:41 +0100 Subject: Issue #1378 - Align the drawing of table cell backgrounds with the spec. --- layout/tables/nsTableCellFrame.cpp | 37 +++++++++--- layout/tables/nsTableCellFrame.h | 8 ++- layout/tables/nsTableFrame.cpp | 115 ++++++++++++++++++++++--------------- 3 files changed, 105 insertions(+), 55 deletions(-) (limited to 'layout') diff --git a/layout/tables/nsTableCellFrame.cpp b/layout/tables/nsTableCellFrame.cpp index 043509fc4..2862bb201 100644 --- a/layout/tables/nsTableCellFrame.cpp +++ b/layout/tables/nsTableCellFrame.cpp @@ -450,19 +450,40 @@ PaintTableCellSelection(nsIFrame* aFrame, DrawTarget* aDrawTarget, aPt); } +bool +nsTableCellFrame::ShouldPaintBordersAndBackgrounds() const +{ + // If we're not visible, we don't paint. + if (!StyleVisibility()->IsVisible()) { + return false; + } + + // Consider 'empty-cells', but only in separated borders mode. + if (!GetContentEmpty()) { + return true; + } + + nsTableFrame* tableFrame = GetTableFrame(); + if (tableFrame->IsBorderCollapse()) { + return true; + } + + return StyleTableBorder()->mEmptyCells == NS_STYLE_TABLE_EMPTY_CELLS_SHOW; +} + +bool +nsTableCellFrame::ShouldPaintBackground(nsDisplayListBuilder* aBuilder) +{ + return ShouldPaintBordersAndBackgrounds() && IsVisibleInSelection(aBuilder); +} + void nsTableCellFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { DO_GLOBAL_REFLOW_COUNT_DSP("nsTableCellFrame"); - nsTableFrame* tableFrame = GetTableFrame(); - int32_t emptyCellStyle = GetContentEmpty() && !tableFrame->IsBorderCollapse() ? - StyleTableBorder()->mEmptyCells - : NS_STYLE_TABLE_EMPTY_CELLS_SHOW; - // take account of 'empty-cells' - if (StyleVisibility()->IsVisible() && - (NS_STYLE_TABLE_EMPTY_CELLS_HIDE != emptyCellStyle)) { + if (ShouldPaintBordersAndBackgrounds()) { // display outset box-shadows if we need to. bool hasBoxShadow = !!StyleEffects()->mBoxShadow; if (hasBoxShadow) { @@ -487,7 +508,7 @@ nsTableCellFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, } // display borders if we need to - ProcessBorders(tableFrame, aBuilder, aLists); + ProcessBorders(GetTableFrame(), aBuilder, aLists); // and display the selection border if we need to if (IsSelected()) { diff --git a/layout/tables/nsTableCellFrame.h b/layout/tables/nsTableCellFrame.h index d8debe993..e8dad5c20 100644 --- a/layout/tables/nsTableCellFrame.h +++ b/layout/tables/nsTableCellFrame.h @@ -209,7 +209,7 @@ public: /** set the desired size returned by this frame during its last reflow */ inline void SetDesiredSize(const ReflowOutput & aDesiredSize); - bool GetContentEmpty(); + bool GetContentEmpty() const; void SetContentEmpty(bool aContentEmpty); bool HasPctOverBSize(); @@ -246,6 +246,10 @@ public: virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0) override; virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0) override; virtual void InvalidateFrameForRemoval() override { InvalidateFrameSubtree(); } + + bool ShouldPaintBordersAndBackgrounds() const; + + bool ShouldPaintBackground(nsDisplayListBuilder* aBuilder); protected: virtual LogicalSides @@ -283,7 +287,7 @@ inline void nsTableCellFrame::SetDesiredSize(const ReflowOutput & aDesiredSize) mDesiredSize = aDesiredSize.Size(wm).ConvertTo(GetWritingMode(), wm); } -inline bool nsTableCellFrame::GetContentEmpty() +inline bool nsTableCellFrame::GetContentEmpty() const { return HasAnyStateBits(NS_TABLE_CELL_CONTENT_EMPTY); } diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index 890d050fd..891d7e7cd 100644 --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -1196,6 +1196,10 @@ PaintRowBackground(nsTableRowFrame* aRow, { // Compute background rect by iterating over all cell frames. for (nsTableCellFrame* cell = aRow->GetFirstCell(); cell; cell = cell->GetNextCell()) { + if (!cell->ShouldPaintBackground(aBuilder)) { + continue; + } + auto cellRect = cell->GetRectRelativeToSelf() + cell->GetNormalPosition() + aOffset; nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, aFrame, cellRect, aLists.BorderBackground(), @@ -1226,6 +1230,10 @@ PaintRowGroupBackgroundByColIdx(nsTableRowGroupFrame* aRowGroup, { for (nsTableRowFrame* row = aRowGroup->GetFirstRow(); row; row = row->GetNextRow()) { for (nsTableCellFrame* cell = row->GetFirstCell(); cell; cell = cell->GetNextCell()) { + if (!cell->ShouldPaintBackground(aBuilder)) { + continue; + } + int32_t curColIdx; cell->GetColIndex(curColIdx); if (aColIdx.Contains(curColIdx)) { @@ -1247,66 +1255,83 @@ nsTableFrame::DisplayGenericTablePart(nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists, DisplayGenericTablePartTraversal aTraversal) { - if (aFrame->IsVisibleForPainting(aBuilder)) { + bool isVisible = aFrame->IsVisibleForPainting(aBuilder); + bool isTable = (aFrame->GetType() == nsGkAtoms::tableFrame); + + if (isVisible || !isTable) { nsDisplayTableItem* currentItem = aBuilder->GetCurrentTableItem(); // currentItem may be null, when none of the table parts have a // background or border if (currentItem) { currentItem->UpdateForFrameBackground(aFrame); } + } + + if (isVisible) { + // XXX: 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 - bool hasBoxShadow = aFrame->StyleEffects()->mBoxShadow != nullptr; - if (hasBoxShadow) { + if (aFrame->StyleEffects()->mBoxShadow) { aLists.BorderBackground()->AppendNewToTop( new (aBuilder) nsDisplayBoxShadowOuter(aBuilder, aFrame)); } + } - if (aFrame->GetType() == nsGkAtoms::tableRowGroupFrame) { - nsTableRowGroupFrame* rowGroup = static_cast(aFrame); - PaintRowGroupBackground(rowGroup, aFrame, aBuilder, aLists); - } else if (aFrame->GetType() == nsGkAtoms::tableRowFrame) { - nsTableRowFrame* row = static_cast(aFrame); - PaintRowBackground(row, aFrame, aBuilder, aLists); - } else if (aFrame->GetType() == nsGkAtoms::tableColGroupFrame) { - // Compute background rect by iterating all cell frame. - nsTableColGroupFrame* colGroup = static_cast(aFrame); - // Collecting column index. - AutoTArray colIdx; - for (nsTableColFrame* col = colGroup->GetFirstColumn(); col; col = col->GetNextCol()) { - colIdx.AppendElement(col->GetColIndex()); - } - - nsTableFrame* table = colGroup->GetTableFrame(); - RowGroupArray rowGroups; - table->OrderRowGroups(rowGroups); - for (nsTableRowGroupFrame* rowGroup : rowGroups) { - auto offset = rowGroup->GetNormalPosition() - colGroup->GetNormalPosition(); - PaintRowGroupBackgroundByColIdx(rowGroup, aFrame, aBuilder, aLists, colIdx, offset); - } - } else if (aFrame->GetType() == nsGkAtoms::tableColFrame) { - // Compute background rect by iterating all cell frame. - nsTableColFrame* col = static_cast(aFrame); - AutoTArray colIdx; + // Background visibility for rows, rowgroups, columns, colgroups depends on + // the visibility of the _cell_, not of the row/col(group). + // See spec at https://drafts.csswg.org/css-tables-3/#drawing-cell-backgrounds + if (aFrame->GetType() == nsGkAtoms::tableRowGroupFrame) { + nsTableRowGroupFrame* rowGroup = static_cast(aFrame); + PaintRowGroupBackground(rowGroup, aFrame, aBuilder, aLists); + } else if (aFrame->GetType() == nsGkAtoms::tableRowFrame) { + nsTableRowFrame* row = static_cast(aFrame); + PaintRowBackground(row, aFrame, aBuilder, aLists); + } else if (aFrame->GetType() == nsGkAtoms::tableColGroupFrame) { + // Compute background rect by iterating all cell frame. + nsTableColGroupFrame* colGroup = static_cast(aFrame); + // Collecting column index. + AutoTArray colIdx; + for (nsTableColFrame* col = colGroup->GetFirstColumn(); col; col = col->GetNextCol()) { 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(); - 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(); + PaintRowGroupBackgroundByColIdx(rowGroup, aFrame, aBuilder, aLists, colIdx, offset); + } + } else if (aFrame->GetType() == nsGkAtoms::tableColFrame) { + // Compute background rect by iterating all cell frame. + nsTableColFrame* col = static_cast(aFrame); + AutoTArray 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(); + PaintRowGroupBackgroundByColIdx(rowGroup, aFrame, aBuilder, aLists, colIdx, offset); } + } else { + nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, aFrame, + aFrame->GetRectRelativeToSelf(), + aLists.BorderBackground()); + } + + if (isVisible) { + // XXX: 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 - if (hasBoxShadow) { + if (aFrame->StyleEffects()->mBoxShadow) { aLists.BorderBackground()->AppendNewToTop( new (aBuilder) nsDisplayBoxShadowInner(aBuilder, aFrame)); } @@ -1314,8 +1339,8 @@ nsTableFrame::DisplayGenericTablePart(nsDisplayListBuilder* aBuilder, aTraversal(aBuilder, aFrame, aDirtyRect, aLists); - if (aFrame->IsVisibleForPainting(aBuilder)) { - if (aFrame->GetType() == nsGkAtoms::tableFrame) { + if (isVisible) { + if (isTable) { nsTableFrame* table = static_cast(aFrame); // In the collapsed border model, overlay all collapsed borders. if (table->IsBorderCollapse()) { -- cgit v1.2.3