diff options
Diffstat (limited to 'layout/tables/nsTableFrame.cpp')
-rw-r--r-- | layout/tables/nsTableFrame.cpp | 293 |
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) { |