summaryrefslogtreecommitdiff
path: root/layout/tables/nsTableFrame.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'layout/tables/nsTableFrame.cpp')
-rw-r--r--layout/tables/nsTableFrame.cpp293
1 files changed, 203 insertions, 90 deletions
diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp
index 32fe38b052..4257c9c579 100644
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -1161,127 +1161,242 @@ nsDisplayTableBorderCollapse::Paint(nsDisplayListBuilder* aBuilder,
static_cast<nsTableFrame*>(mFrame)->PaintBCBorders(*drawTarget, mVisibleRect - pt);
}
-static inline bool FrameHasBorder(nsIFrame* f) {
- if (!f->StyleVisibility()->IsVisible()) {
- return false;
+/* static */ void
+nsTableFrame::GenericTraversal(nsDisplayListBuilder* aBuilder, nsFrame* aFrame,
+ const nsRect& aDirtyRect, const nsDisplayListSet& aLists)
+{
+ // This is similar to what nsContainerFrame::BuildDisplayListForNonBlockChildren
+ // does, except that we allow the children's background and borders to go
+ // in our BorderBackground list. This doesn't really affect background
+ // painting --- the children won't actually draw their own backgrounds
+ // because the nsTableFrame already drew them, unless a child has its own
+ // stacking context, in which case the child won't use its passed-in
+ // BorderBackground list anyway. It does affect cell borders though; this
+ // lets us get cell borders into the nsTableFrame's BorderBackground list.
+ for (nsIFrame* kid : aFrame->GetChildList(kColGroupList)) {
+ aFrame->BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
}
- if (f->StyleBorder()->HasBorder()) {
- return true;
+ for (nsIFrame* kid : aFrame->PrincipalChildList()) {
+ aFrame->BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
}
+}
- return false;
+static void
+PaintRowBackground(nsTableRowFrame* aRow,
+ nsIFrame* aFrame,
+ nsDisplayListBuilder* aBuilder,
+ const nsDisplayListSet& aLists,
+ const nsRect& aDirtyRect,
+ const nsPoint& aOffset = nsPoint())
+{
+ // 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;
+ if (!aDirtyRect.Intersects(cellRect)) {
+ continue;
+ }
+ nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, aFrame, cellRect,
+ aLists.BorderBackground(),
+ true, nullptr,
+ aFrame->GetRectRelativeToSelf(),
+ cell);
+ }
}
-void nsTableFrame::CalcHasBCBorders() {
- if (!IsBorderCollapse()) {
- SetHasBCBorders(false);
- return;
+static void
+PaintRowGroupBackground(nsTableRowGroupFrame* aRowGroup,
+ nsIFrame* aFrame,
+ nsDisplayListBuilder* aBuilder,
+ const nsDisplayListSet& aLists,
+ const nsRect& aDirtyRect)
+{
+ for (nsTableRowFrame* row = aRowGroup->GetFirstRow(); row; row = row->GetNextRow()) {
+ if (!aDirtyRect.Intersects(nsRect(row->GetNormalPosition(), row->GetSize()))) {
+ continue;
+ }
+ PaintRowBackground(row, aFrame, aBuilder, aLists, aDirtyRect, row->GetNormalPosition());
}
+}
- if (FrameHasBorder(this)) {
- SetHasBCBorders(true);
- return;
+static void
+PaintRowGroupBackgroundByColIdx(nsTableRowGroupFrame* aRowGroup,
+ nsIFrame* aFrame,
+ nsDisplayListBuilder* aBuilder,
+ const nsDisplayListSet& aLists,
+ const nsRect& aDirtyRect,
+ const nsTArray<uint32_t>& aColIdx,
+ const nsPoint& aOffset)
+{
+ MOZ_DIAGNOSTIC_ASSERT(!aColIdx.IsEmpty(),
+ "Must be painting backgrounds for something");
+ for (nsTableRowFrame* row = aRowGroup->GetFirstRow(); row; row = row->GetNextRow()) {
+ auto rowPos = row->GetNormalPosition() + aOffset;
+ if (!aDirtyRect.Intersects(nsRect(rowPos, row->GetSize()))) {
+ continue;
+ }
+ for (nsTableCellFrame* cell = row->GetFirstCell(); cell; cell = cell->GetNextCell()) {
+
+ uint32_t curColIdx = cell->ColIndex();
+ if (!aColIdx.Contains(curColIdx)) {
+ if (curColIdx > aColIdx.LastElement()) {
+ // We can just stop looking at this row.
+ break;
+ }
+ continue;
+ }
+
+ if (!cell->ShouldPaintBackground(aBuilder)) {
+ continue;
+ }
+
+ auto cellPos = cell->GetNormalPosition() + rowPos;
+ auto cellRect = nsRect(cellPos, cell->GetSize());
+ if (!aDirtyRect.Intersects(cellRect)) {
+ continue;
+ }
+ nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, aFrame, cellRect,
+ aLists.BorderBackground(),
+ true, nullptr,
+ aFrame->GetRectRelativeToSelf(),
+ cell);
+ }
}
+}
- // Check col and col group has borders.
- for (nsIFrame* f : this->GetChildList(kColGroupList)) {
- if (FrameHasBorder(f)) {
- SetHasBCBorders(true);
- return;
+/* static */ void
+nsTableFrame::DisplayGenericTablePart(nsDisplayListBuilder* aBuilder,
+ nsFrame* aFrame,
+ const nsRect& aDirtyRect,
+ const nsDisplayListSet& aLists,
+ DisplayGenericTablePartTraversal aTraversal)
+{
+ 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
+ if (aFrame->StyleEffects()->mBoxShadow) {
+ aLists.BorderBackground()->AppendNewToTop(
+ new (aBuilder) nsDisplayBoxShadowOuter(aBuilder, aFrame));
+ }
+ }
+
+ // 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<nsTableRowGroupFrame*>(aFrame);
+ PaintRowGroupBackground(rowGroup, aFrame, aBuilder, aLists, aDirtyRect);
+ } else if (aFrame->GetType() == nsGkAtoms::tableRowFrame) {
+ nsTableRowFrame* row = static_cast<nsTableRowFrame*>(aFrame);
+ PaintRowBackground(row, aFrame, aBuilder, aLists, aDirtyRect);
+ } else if (aFrame->GetType() == nsGkAtoms::tableColGroupFrame) {
+ // Compute background rect by iterating all cell frame.
+ nsTableColGroupFrame* colGroup = static_cast<nsTableColGroupFrame*>(aFrame);
+ // Collecting column index.
+ AutoTArray<uint32_t, 1> colIdx;
+ for (nsTableColFrame* col = colGroup->GetFirstColumn(); col; col = col->GetNextCol()) {
+ MOZ_ASSERT(colIdx.IsEmpty() ||
+ static_cast<uint32_t>(col->GetColIndex()) > colIdx.LastElement());
+ colIdx.AppendElement(col->GetColIndex());
+ }
+
+ if (!colIdx.IsEmpty()) {
+ // We have some actual cells that live inside this rowgroup.
+ nsTableFrame* table = colGroup->GetTableFrame();
+ RowGroupArray rowGroups;
+ table->OrderRowGroups(rowGroups);
+ for (nsTableRowGroupFrame* rowGroup : rowGroups) {
+ auto offset = rowGroup->GetNormalPosition() - colGroup->GetNormalPosition();
+ if (!aDirtyRect.Intersects(nsRect(offset, rowGroup->GetSize()))) {
+ continue;
+ }
+ PaintRowGroupBackgroundByColIdx(rowGroup, aFrame, aBuilder, aLists, aDirtyRect, colIdx, offset);
+ }
}
+ } else if (aFrame->GetType() == nsGkAtoms::tableColFrame) {
+ // Compute background rect by iterating all cell frame.
+ nsTableColFrame* col = static_cast<nsTableColFrame*>(aFrame);
+ AutoTArray<uint32_t, 1> colIdx;
+ colIdx.AppendElement(col->GetColIndex());
- nsTableColGroupFrame* colGroup = static_cast<nsTableColGroupFrame*>(f);
- for (nsTableColFrame* col = colGroup->GetFirstColumn(); col;
- col = col->GetNextCol()) {
- if (FrameHasBorder(col)) {
- SetHasBCBorders(true);
- return;
+ nsTableFrame* table = col->GetTableFrame();
+ RowGroupArray rowGroups;
+ table->OrderRowGroups(rowGroups);
+ for (nsTableRowGroupFrame* rowGroup : rowGroups) {
+ auto offset = rowGroup->GetNormalPosition() -
+ col->GetNormalPosition() -
+ col->GetTableColGroupFrame()->GetNormalPosition();
+ if (!aDirtyRect.Intersects(nsRect(offset, rowGroup->GetSize()))) {
+ continue;
}
+ PaintRowGroupBackgroundByColIdx(rowGroup, aFrame, aBuilder, aLists, aDirtyRect, colIdx, offset);
}
+ } else if (isVisible) {
+ nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, aFrame,
+ aFrame->GetRectRelativeToSelf(),
+ aLists.BorderBackground());
}
- // check row group, row and cell has borders.
- RowGroupArray rowGroups;
- OrderRowGroups(rowGroups);
- for (nsTableRowGroupFrame* rowGroup : rowGroups) {
- if (FrameHasBorder(rowGroup)) {
- SetHasBCBorders(true);
- return;
+ 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 (aFrame->StyleEffects()->mBoxShadow) {
+ aLists.BorderBackground()->AppendNewToTop(
+ new (aBuilder) nsDisplayBoxShadowInner(aBuilder, aFrame));
}
+ }
- for (nsTableRowFrame* row = rowGroup->GetFirstRow(); row;
- row = row->GetNextRow()) {
- if (FrameHasBorder(row)) {
- SetHasBCBorders(true);
- return;
- }
+ aTraversal(aBuilder, aFrame, aDirtyRect, aLists);
- for (nsTableCellFrame* cell = row->GetFirstCell(); cell;
- cell = cell->GetNextCell()) {
- if (FrameHasBorder(cell)) {
- SetHasBCBorders(true);
- return;
- }
+ if (isVisible) {
+ if (isTable) {
+ nsTableFrame* table = static_cast<nsTableFrame*>(aFrame);
+ // In the collapsed border model, overlay all collapsed borders.
+ if (table->IsBorderCollapse()) {
+ aLists.BorderBackground()->AppendNewToTop(
+ new (aBuilder) nsDisplayTableBorderCollapse(aBuilder, table));
+ } else {
+ aLists.BorderBackground()->AppendNewToTop(
+ new (aBuilder) nsDisplayBorder(aBuilder, table));
}
}
}
- SetHasBCBorders(false);
+ aFrame->DisplayOutline(aBuilder, aLists);
}
// table paint code is concerned primarily with borders and bg color
// SEC: TODO: adjust the rect for captions
void
nsTableFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
+ const nsRect& aDirtyRect,
const nsDisplayListSet& aLists)
{
DO_GLOBAL_REFLOW_COUNT_DSP_COLOR("nsTableFrame", NS_RGB(255,128,255));
- DisplayBorderBackgroundOutline(aBuilder, aLists);
-
- nsDisplayTableBackgroundSet tableBGs(aBuilder, this);
- nsDisplayListCollection lists(aBuilder);
-
-// This is similar to what
- // nsContainerFrame::BuildDisplayListForNonBlockChildren does, except that we
- // allow the children's background and borders to go in our BorderBackground
- // list. This doesn't really affect background painting --- the children won't
- // actually draw their own backgrounds because the nsTableFrame already drew
- // them, unless a child has its own stacking context, in which case the child
- // won't use its passed-in BorderBackground list anyway. It does affect cell
- // borders though; this lets us get cell borders into the nsTableFrame's
- // BorderBackground list.
- for (nsIFrame* colGroup : FirstContinuation()->GetChildList(kColGroupList)) {
- for (nsIFrame* col : colGroup->PrincipalChildList()) {
- tableBGs.AddColumn((nsTableColFrame*)col);
- }
- }
-
- for (nsIFrame* kid : PrincipalChildList()) {
- BuildDisplayListForChild(aBuilder, kid, lists);
- }
-
- tableBGs.MoveTo(aLists);
- lists.MoveTo(aLists);
-
- if (IsVisibleForPainting(aBuilder)) {
- // In the collapsed border model, overlay all collapsed borders.
- if (IsBorderCollapse()) {
- if (HasBCBorders()) {
- aLists.BorderBackground()->AppendNewToTop(
- new (aBuilder) nsDisplayTableBorderCollapse
- (aBuilder, this));
- }
- } else {
- const nsStyleBorder* borderStyle = StyleBorder();
- if (borderStyle->HasBorder()) {
- aLists.BorderBackground()->AppendNewToTop(
- new (aBuilder) nsDisplayBorder
- (aBuilder, this));
- }
- }
- }
+ DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists);
}
nsMargin
@@ -3986,7 +4101,6 @@ nsTableFrame::AddBCDamageArea(const TableArea& aValue)
#endif
SetNeedToCalcBCBorders(true);
- SetNeedToCalcHasBCBorders(true);
// Get the property
BCPropertyData* value = GetOrCreateBCProperty();
if (value) {
@@ -4027,7 +4141,6 @@ nsTableFrame::SetFullBCDamageArea()
NS_ASSERTION(IsBorderCollapse(), "invalid SetFullBCDamageArea call");
SetNeedToCalcBCBorders(true);
- SetNeedToCalcHasBCBorders(true);
BCPropertyData* value = GetOrCreateBCProperty();
if (value) {