diff options
Diffstat (limited to 'layout/tables')
-rw-r--r-- | layout/tables/nsTableCellFrame.cpp | 54 | ||||
-rw-r--r-- | layout/tables/nsTableCellFrame.h | 1 | ||||
-rw-r--r-- | layout/tables/nsTableColFrame.cpp | 9 | ||||
-rw-r--r-- | layout/tables/nsTableColFrame.h | 1 | ||||
-rw-r--r-- | layout/tables/nsTableColGroupFrame.cpp | 9 | ||||
-rw-r--r-- | layout/tables/nsTableColGroupFrame.h | 1 | ||||
-rw-r--r-- | layout/tables/nsTableFrame.cpp | 293 | ||||
-rw-r--r-- | layout/tables/nsTableFrame.h | 130 | ||||
-rw-r--r-- | layout/tables/nsTableRowFrame.cpp | 58 | ||||
-rw-r--r-- | layout/tables/nsTableRowFrame.h | 6 | ||||
-rw-r--r-- | layout/tables/nsTableRowGroupFrame.cpp | 52 | ||||
-rw-r--r-- | layout/tables/nsTableRowGroupFrame.h | 1 | ||||
-rw-r--r-- | layout/tables/nsTableWrapperFrame.cpp | 13 | ||||
-rw-r--r-- | layout/tables/nsTableWrapperFrame.h | 2 |
14 files changed, 293 insertions, 337 deletions
diff --git a/layout/tables/nsTableCellFrame.cpp b/layout/tables/nsTableCellFrame.cpp index 9c715d999..8b811df1e 100644 --- a/layout/tables/nsTableCellFrame.cpp +++ b/layout/tables/nsTableCellFrame.cpp @@ -450,6 +450,7 @@ nsTableCellFrame::ShouldPaintBackground(nsDisplayListBuilder* aBuilder) void nsTableCellFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { DO_GLOBAL_REFLOW_COUNT_DSP("nsTableCellFrame"); @@ -461,14 +462,14 @@ nsTableCellFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, new (aBuilder) nsDisplayBoxShadowOuter(aBuilder, this)); } - nsRect bgRect = GetRectRelativeToSelf() + aBuilder->ToReferenceFrame(this); - // display background if we need to. if (aBuilder->IsForEventDelivery() || !StyleBackground()->IsTransparent() || StyleDisplay()->mAppearance) { - nsDisplayBackgroundImage::AppendBackgroundItemsToTop( - aBuilder, this, bgRect, aLists.BorderBackground()); + nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, + this, + GetRectRelativeToSelf(), + aLists.BorderBackground()); } // display inset box-shadows if we need to. @@ -487,49 +488,16 @@ nsTableCellFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, "TableCellSelection", nsDisplayItem::TYPE_TABLE_CELL_SELECTION)); } - - // This can be null if display list building initiated in the middle - // of the table, which can happen with background-clip:text and - // -moz-element. - nsDisplayTableBackgroundSet* backgrounds = - aBuilder->GetTableBackgroundSet(); - if (backgrounds) { - // Compute bgRect relative to reference frame, but using the - // normal (without position:relative offsets) positions for the - // cell, row and row group. - bgRect = GetRectRelativeToSelf() + GetNormalPosition(); - - nsTableRowFrame* row = GetTableRowFrame(); - bgRect += row->GetNormalPosition(); - - nsTableRowGroupFrame* rowGroup = row->GetTableRowGroupFrame(); - bgRect += rowGroup->GetNormalPosition(); - - bgRect += backgrounds->TableToReferenceFrame(); - - // Create backgrounds items as needed for the column and column - // group that this cell occupies. - nsTableColFrame* col = backgrounds->GetColForIndex(ColIndex()); - nsTableColGroupFrame* colGroup = col->GetTableColGroupFrame(); - - Maybe<nsDisplayListBuilder::AutoBuildingDisplayList> buildingForColGroup; - nsDisplayBackgroundImage::AppendBackgroundItemsToTop( - aBuilder, colGroup, bgRect, backgrounds->ColGroupBackgrounds(), false, - nullptr, colGroup->GetRect() + backgrounds->TableToReferenceFrame(), - this, &buildingForColGroup); - - Maybe<nsDisplayListBuilder::AutoBuildingDisplayList> buildingForCol; - nsDisplayBackgroundImage::AppendBackgroundItemsToTop( - aBuilder, col, bgRect, backgrounds->ColBackgrounds(), false, nullptr, - col->GetRect() + colGroup->GetPosition() + - backgrounds->TableToReferenceFrame(), - this, &buildingForCol); - } } // the 'empty-cells' property has no effect on 'outline' DisplayOutline(aBuilder, aLists); + // Push a null 'current table item' so that descendant tables can't + // accidentally mess with our table + nsAutoPushCurrentTableItem pushTableItem; + pushTableItem.Push(aBuilder, nullptr); + nsIFrame* kid = mFrames.FirstChild(); NS_ASSERTION(kid && !kid->GetNextSibling(), "Table cells should have just one child"); // The child's background will go in our BorderBackground() list. @@ -538,7 +506,7 @@ nsTableCellFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, // because that/ would put the child's background in the Content() list // which isn't right (e.g., would end up on top of our child floats for // event handling). - BuildDisplayListForChild(aBuilder, kid, aLists); + BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists); } nsIFrame::LogicalSides diff --git a/layout/tables/nsTableCellFrame.h b/layout/tables/nsTableCellFrame.h index a822e309d..f626a45b0 100644 --- a/layout/tables/nsTableCellFrame.h +++ b/layout/tables/nsTableCellFrame.h @@ -104,6 +104,7 @@ public: virtual bool NeedsToObserve(const ReflowInput& aReflowInput) override; virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, const nsDisplayListSet& aLists) override; virtual nsresult ProcessBorders(nsTableFrame* aFrame, diff --git a/layout/tables/nsTableColFrame.cpp b/layout/tables/nsTableColFrame.cpp index 6723f4701..54b03522b 100644 --- a/layout/tables/nsTableColFrame.cpp +++ b/layout/tables/nsTableColFrame.cpp @@ -110,15 +110,10 @@ nsTableColFrame::Reflow(nsPresContext* aPresContext, void nsTableColFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { - // Per https://drafts.csswg.org/css-tables-3/#global-style-overrides: - // "All css properties of table-column and table-column-group boxes are - // ignored, except when explicitly specified by this specification." - // CSS outlines and box-shadows fall into this category, so we skip them - // on these boxes. - - MOZ_ASSERT_UNREACHABLE("Cols don't paint themselves"); + nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists); } int32_t nsTableColFrame::GetSpan() diff --git a/layout/tables/nsTableColFrame.h b/layout/tables/nsTableColFrame.h index ed6a843b6..fb989061f 100644 --- a/layout/tables/nsTableColFrame.h +++ b/layout/tables/nsTableColFrame.h @@ -60,6 +60,7 @@ public: nsReflowStatus& aStatus) override; virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, const nsDisplayListSet& aLists) override; /** diff --git a/layout/tables/nsTableColGroupFrame.cpp b/layout/tables/nsTableColGroupFrame.cpp index be5b71bb2..6ee7f0b24 100644 --- a/layout/tables/nsTableColGroupFrame.cpp +++ b/layout/tables/nsTableColGroupFrame.cpp @@ -385,15 +385,10 @@ nsTableColGroupFrame::Reflow(nsPresContext* aPresContext, void nsTableColGroupFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { - // Per https://drafts.csswg.org/css-tables-3/#global-style-overrides: - // "All css properties of table-column and table-column-group boxes are - // ignored, except when explicitly specified by this specification." - // CSS outlines and box-shadows fall into this category, so we skip them - // on these boxes. - - MOZ_ASSERT_UNREACHABLE("Colgroups don't paint themselves"); + nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists); } nsTableColFrame * nsTableColGroupFrame::GetFirstColumn() diff --git a/layout/tables/nsTableColGroupFrame.h b/layout/tables/nsTableColGroupFrame.h index 88ed67c2a..b3dfb94e7 100644 --- a/layout/tables/nsTableColGroupFrame.h +++ b/layout/tables/nsTableColGroupFrame.h @@ -44,6 +44,7 @@ public: } virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, const nsDisplayListSet& aLists) override; /** A colgroup can be caused by three things: diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index 32fe38b05..4257c9c57 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) { diff --git a/layout/tables/nsTableFrame.h b/layout/tables/nsTableFrame.h index 7fcdcb9d8..a6b786402 100644 --- a/layout/tables/nsTableFrame.h +++ b/layout/tables/nsTableFrame.h @@ -72,59 +72,36 @@ private: bool mDrawsBackground; }; -class nsDisplayTableBackgroundSet { - public: - nsDisplayList* ColGroupBackgrounds() { return &mColGroupBackgrounds; } - - nsDisplayList* ColBackgrounds() { return &mColBackgrounds; } - - nsDisplayTableBackgroundSet(nsDisplayListBuilder* aBuilder, nsIFrame* aTable) - : mBuilder(aBuilder) { - mPrevTableBackgroundSet = mBuilder->SetTableBackgroundSet(this); - mozilla::DebugOnly<const nsIFrame*> reference = - mBuilder->FindReferenceFrameFor(aTable, &mToReferenceFrame); - MOZ_ASSERT(nsLayoutUtils::IsAncestorFrameCrossDoc(reference, aTable)); - mDirtyRect = mBuilder->GetDirtyRect(); - } +class nsAutoPushCurrentTableItem +{ +public: + nsAutoPushCurrentTableItem() : mBuilder(nullptr) {} - ~nsDisplayTableBackgroundSet() { - mozilla::DebugOnly<nsDisplayTableBackgroundSet*> result = - mBuilder->SetTableBackgroundSet(mPrevTableBackgroundSet); - MOZ_ASSERT(result == this); + void Push(nsDisplayListBuilder* aBuilder, nsDisplayTableItem* aPushItem) + { + mBuilder = aBuilder; + mOldCurrentItem = aBuilder->GetCurrentTableItem(); + aBuilder->SetCurrentTableItem(aPushItem); +#ifdef DEBUG + mPushedItem = aPushItem; +#endif } - - /** - * Move all display items in our lists to top of the corresponding lists in - * the destination. - */ - void MoveTo(const nsDisplayListSet& aDestination) { - aDestination.BorderBackground()->AppendToTop(ColGroupBackgrounds()); - aDestination.BorderBackground()->AppendToTop(ColBackgrounds()); + ~nsAutoPushCurrentTableItem() { + if (!mBuilder) + return; +#ifdef DEBUG + NS_ASSERTION(mBuilder->GetCurrentTableItem() == mPushedItem, + "Someone messed with the current table item behind our back!"); +#endif + mBuilder->SetCurrentTableItem(mOldCurrentItem); } - void AddColumn(nsTableColFrame* aFrame) { mColumns.AppendElement(aFrame); } - - nsTableColFrame* GetColForIndex(int32_t aIndex) { return mColumns[aIndex]; } - - const nsPoint& TableToReferenceFrame() { return mToReferenceFrame; } - - const nsRect& GetDirtyRect() { return mDirtyRect; } - - private: - // This class is only used on stack, so we don't have to worry about leaking - // it. Don't let us be heap-allocated! - void* operator new(size_t sz) CPP_THROW_NEW; - - protected: +private: nsDisplayListBuilder* mBuilder; - nsDisplayTableBackgroundSet* mPrevTableBackgroundSet; - - nsDisplayList mColGroupBackgrounds; - nsDisplayList mColBackgrounds; - - nsTArray<nsTableColFrame*> mColumns; - nsPoint mToReferenceFrame; - nsRect mDirtyRect; + nsDisplayTableItem* mOldCurrentItem; +#ifdef DEBUG + nsDisplayTableItem* mPushedItem; +#endif }; /* ============================================================================ */ @@ -252,6 +229,29 @@ public: nsIFrame* aSourceFrame, bool* aDidPassThrough); + typedef void (* DisplayGenericTablePartTraversal) + (nsDisplayListBuilder* aBuilder, nsFrame* aFrame, + const nsRect& aDirtyRect, const nsDisplayListSet& aLists); + static void GenericTraversal(nsDisplayListBuilder* aBuilder, nsFrame* aFrame, + const nsRect& aDirtyRect, const nsDisplayListSet& aLists); + + /** + * Helper method to handle display common to table frames, rowgroup frames + * and row frames. It creates a background display item for handling events + * if necessary, an outline display item if necessary, and displays + * all the the frame's children. + * @param aDisplayItem the display item created for this part, or null + * if this part's border/background painting is delegated to an ancestor + * @param aTraversal a function that gets called to traverse the table + * part's child frames and add their display list items to a + * display list set. + */ + static void DisplayGenericTablePart(nsDisplayListBuilder* aBuilder, + nsFrame* aFrame, + const nsRect& aDirtyRect, + const nsDisplayListSet& aLists, + DisplayGenericTablePartTraversal aTraversal = GenericTraversal); + // Return the closest sibling of aPriorChildFrame (including aPriroChildFrame) // of type aChildType. static nsIFrame* GetFrameAtOrBefore(nsIFrame* aParentFrame, @@ -268,6 +268,7 @@ public: virtual void GetChildLists(nsTArray<ChildList>* aLists) const override; virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, const nsDisplayListSet& aLists) override; /** Get the outer half (i.e., the part outside the height and width of @@ -760,13 +761,6 @@ public: bool NeedToCollapse() const; void SetNeedToCollapse(bool aValue); - bool NeedToCalcHasBCBorders() const; - void SetNeedToCalcHasBCBorders(bool aValue); - - void CalcHasBCBorders(); - bool HasBCBorders(); - void SetHasBCBorders(bool aValue); - /** The GeometryDirty bit is similar to the NS_FRAME_IS_DIRTY frame * state bit, which implies that all descendants are dirty. The * GeometryDirty still implies that all the parts of the table are @@ -876,8 +870,6 @@ protected: uint32_t mIStartContBCBorder:8; uint32_t mNeedToCollapse:1; // rows, cols that have visibility:collapse need to be collapsed uint32_t mResizedColumns:1; // have we resized columns since last reflow? - uint32_t mNeedToCalcHasBCBorders:1; - uint32_t mHasBCBorders:1; } mBits; nsTableCellMap* mCellMap; // maintains the relationships between rows, cols, and cells @@ -973,30 +965,6 @@ inline void nsTableFrame::SetNeedToCalcBCBorders(bool aValue) mBits.mNeedToCalcBCBorders = (unsigned)aValue; } -inline bool nsTableFrame::NeedToCalcHasBCBorders() const -{ - return (bool)mBits.mNeedToCalcHasBCBorders; -} - -inline void nsTableFrame::SetNeedToCalcHasBCBorders(bool aValue) -{ - mBits.mNeedToCalcHasBCBorders = (unsigned)aValue; -} - -inline bool nsTableFrame::HasBCBorders() -{ - if (NeedToCalcHasBCBorders()) { - CalcHasBCBorders(); - SetNeedToCalcHasBCBorders(false); - } - return (bool)mBits.mHasBCBorders; -} - -inline void nsTableFrame::SetHasBCBorders(bool aValue) -{ - mBits.mHasBCBorders = (unsigned)aValue; -} - inline nscoord nsTableFrame::GetContinuousIStartBCBorderWidth() const { diff --git a/layout/tables/nsTableRowFrame.cpp b/layout/tables/nsTableRowFrame.cpp index 18f11f876..02b85a141 100644 --- a/layout/tables/nsTableRowFrame.cpp +++ b/layout/tables/nsTableRowFrame.cpp @@ -549,66 +549,12 @@ nsTableRowFrame::CalcBSize(const ReflowInput& aReflowInput) return GetInitialBSize(); } -void nsTableRowFrame::PaintCellBackgroundsForFrame( - nsIFrame* aFrame, nsDisplayListBuilder* aBuilder, - const nsDisplayListSet& aLists, const nsPoint& aOffset) { - // Compute background rect by iterating all cell frame. - const nsPoint toReferenceFrame = aBuilder->ToReferenceFrame(aFrame); - for (nsTableCellFrame* cell = GetFirstCell(); cell; - cell = cell->GetNextCell()) { - if (!cell->ShouldPaintBackground(aBuilder)) { - continue; - } - - auto cellRect = - cell->GetRectRelativeToSelf() + cell->GetNormalPosition() + aOffset; - if (!aBuilder->GetDirtyRect().Intersects(cellRect)) { - continue; - } - cellRect += toReferenceFrame; - nsDisplayBackgroundImage::AppendBackgroundItemsToTop( - aBuilder, aFrame, cellRect, aLists.BorderBackground(), true, nullptr, - aFrame->GetRectRelativeToSelf() + toReferenceFrame, cell); - } -} - void nsTableRowFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { - if (IsVisibleForPainting(aBuilder)) { - // 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 - if (StyleEffects()->mBoxShadow) { - aLists.BorderBackground()->AppendNewToTop( - new (aBuilder) nsDisplayBoxShadowOuter - (aBuilder, this)); - } - } - - PaintCellBackgroundsForFrame(this, aBuilder, aLists); - - if (IsVisibleForPainting(aBuilder)) { - // 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 - if (StyleEffects()->mBoxShadow) { - aLists.BorderBackground()->AppendNewToTop( - new (aBuilder) nsDisplayBoxShadowInner - (aBuilder, this)); - } - } - - DisplayOutline(aBuilder, aLists); - - for (nsIFrame* kid : PrincipalChildList()) { - BuildDisplayListForChild(aBuilder, kid, aLists); - } + nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists); } nsIFrame::LogicalSides diff --git a/layout/tables/nsTableRowFrame.h b/layout/tables/nsTableRowFrame.h index 4b6dd2628..c53c81ff1 100644 --- a/layout/tables/nsTableRowFrame.h +++ b/layout/tables/nsTableRowFrame.h @@ -79,13 +79,9 @@ public: virtual nsMargin GetUsedPadding() const override; virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, const nsDisplayListSet& aLists) override; - void PaintCellBackgroundsForFrame(nsIFrame* aFrame, - nsDisplayListBuilder* aBuilder, - const nsDisplayListSet& aLists, - const nsPoint& aOffset = nsPoint()); - // Implemented in nsTableCellFrame.h, because it needs to know about the // nsTableCellFrame class, but we can't include nsTableCellFrame.h here. inline nsTableCellFrame* GetFirstCell() const; diff --git a/layout/tables/nsTableRowGroupFrame.cpp b/layout/tables/nsTableRowGroupFrame.cpp index 56ca394de..37f577f5c 100644 --- a/layout/tables/nsTableRowGroupFrame.cpp +++ b/layout/tables/nsTableRowGroupFrame.cpp @@ -156,7 +156,7 @@ nsTableRowGroupFrame::InitRepeatedFrame(nsTableRowGroupFrame* aHeaderFooterFrame // Handle the child-traversal part of DisplayGenericTablePart static void DisplayRows(nsDisplayListBuilder* aBuilder, nsFrame* aFrame, - const nsDisplayListSet& aLists) + const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { nscoord overflowAbove; nsTableRowGroupFrame* f = static_cast<nsTableRowGroupFrame*>(aFrame); @@ -168,16 +168,16 @@ DisplayRows(nsDisplayListBuilder* aBuilder, nsFrame* aFrame, // the rows in |f|, but that's exactly what we're trying to avoid, so we // approximate it by checking it for |f|: if it's true for any row // in |f| then it's true for |f| itself. - nsIFrame* kid = aBuilder->ShouldDescendIntoFrame(f, true) ? - nullptr : f->GetFirstRowContaining(aBuilder->GetVisibleRect().y, &overflowAbove); + nsIFrame* kid = aBuilder->ShouldDescendIntoFrame(f) ? + nullptr : f->GetFirstRowContaining(aDirtyRect.y, &overflowAbove); if (kid) { // If we have a cursor, use it while (kid) { - if (kid->GetRect().y - overflowAbove >= aBuilder->GetDirtyRect().YMost()) { + if (kid->GetRect().y - overflowAbove >= aDirtyRect.YMost()) { break; } - f->BuildDisplayListForChild(aBuilder, kid, aLists); + f->BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists); kid = kid->GetNextSibling(); } return; @@ -187,7 +187,7 @@ DisplayRows(nsDisplayListBuilder* aBuilder, nsFrame* aFrame, nsTableRowGroupFrame::FrameCursorData* cursor = f->SetupRowCursor(); kid = f->PrincipalChildList().FirstChild(); while (kid) { - f->BuildDisplayListForChild(aBuilder, kid, aLists); + f->BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists); if (cursor) { if (!cursor->AppendFrame(kid)) { @@ -205,45 +205,11 @@ DisplayRows(nsDisplayListBuilder* aBuilder, nsFrame* aFrame, void nsTableRowGroupFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { - if (IsVisibleForPainting(aBuilder)) { - // 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 - if (StyleEffects()->mBoxShadow) { - aLists.BorderBackground()->AppendNewToTop( - new (aBuilder) nsDisplayBoxShadowOuter - (aBuilder, this)); - } - } - - for (nsTableRowFrame* row = GetFirstRow(); row; row = row->GetNextRow()) { - if (!aBuilder->GetDirtyRect().Intersects(row->GetVisualOverflowRect() + row->GetNormalPosition())) { - continue; - } - row->PaintCellBackgroundsForFrame(this, aBuilder, aLists, - row->GetNormalPosition()); - } - - if (IsVisibleForPainting(aBuilder)) { - // 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 - if (StyleEffects()->mBoxShadow) { - aLists.BorderBackground()->AppendNewToTop( - new (aBuilder) nsDisplayBoxShadowInner - (aBuilder, this)); - } - } - - DisplayOutline(aBuilder, aLists); - - DisplayRows(aBuilder, this, aLists); + nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect, + aLists, DisplayRows); } nsIFrame::LogicalSides diff --git a/layout/tables/nsTableRowGroupFrame.h b/layout/tables/nsTableRowGroupFrame.h index eb9f6205e..721d91046 100644 --- a/layout/tables/nsTableRowGroupFrame.h +++ b/layout/tables/nsTableRowGroupFrame.h @@ -75,6 +75,7 @@ public: virtual nsMargin GetUsedPadding() const override; virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, const nsDisplayListSet& aLists) override; /** calls Reflow for all of its child rows. diff --git a/layout/tables/nsTableWrapperFrame.cpp b/layout/tables/nsTableWrapperFrame.cpp index 476024e96..da71375d5 100644 --- a/layout/tables/nsTableWrapperFrame.cpp +++ b/layout/tables/nsTableWrapperFrame.cpp @@ -168,6 +168,7 @@ nsTableWrapperFrame::RemoveFrame(ChildListID aListID, void nsTableWrapperFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { // No border, background or outline are painted because they all belong @@ -176,15 +177,16 @@ nsTableWrapperFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, // If there's no caption, take a short cut to avoid having to create // the special display list set and then sort it. if (mCaptionFrames.IsEmpty()) { - BuildDisplayListForInnerTable(aBuilder, aLists); + BuildDisplayListForInnerTable(aBuilder, aDirtyRect, aLists); return; } - nsDisplayListCollection set(aBuilder); - BuildDisplayListForInnerTable(aBuilder, set); + nsDisplayListCollection set; + BuildDisplayListForInnerTable(aBuilder, aDirtyRect, set); nsDisplayListSet captionSet(set, set.BlockBorderBackgrounds()); - BuildDisplayListForChild(aBuilder, mCaptionFrames.FirstChild(), captionSet); + BuildDisplayListForChild(aBuilder, mCaptionFrames.FirstChild(), + aDirtyRect, captionSet); // Now we have to sort everything by content order, since the caption // may be somewhere inside the table @@ -198,6 +200,7 @@ nsTableWrapperFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, void nsTableWrapperFrame::BuildDisplayListForInnerTable(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { // Just paint the regular children, but the children's background is our @@ -205,7 +208,7 @@ nsTableWrapperFrame::BuildDisplayListForInnerTable(nsDisplayListBuilder* aBuil nsIFrame* kid = mFrames.FirstChild(); // The children should be in content order while (kid) { - BuildDisplayListForChild(aBuilder, kid, aLists); + BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists); kid = kid->GetNextSibling(); } } diff --git a/layout/tables/nsTableWrapperFrame.h b/layout/tables/nsTableWrapperFrame.h index 8095c7fc4..45d7c33e4 100644 --- a/layout/tables/nsTableWrapperFrame.h +++ b/layout/tables/nsTableWrapperFrame.h @@ -59,9 +59,11 @@ public: #endif virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, const nsDisplayListSet& aLists) override; void BuildDisplayListForInnerTable(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, const nsDisplayListSet& aLists); virtual nscoord GetLogicalBaseline(mozilla::WritingMode aWritingMode) const override; |