diff options
author | wolfbeast <mcwerewolf@wolfbeast.com> | 2020-04-14 21:49:04 +0200 |
---|---|---|
committer | wolfbeast <mcwerewolf@wolfbeast.com> | 2020-04-14 21:49:04 +0200 |
commit | 39dac57259cff8b61db0b22cb2ad0a8adb02692e (patch) | |
tree | 52a026cc8c22793eb17fd0f5e22adce1ae08a1dd /layout/tables | |
parent | a1cce3b2b00bbd9f4983013ddd8934a7bccb9e99 (diff) | |
parent | c2d9ab62f3d097c9e0e00184cab1f546554f5eaa (diff) | |
download | UXP-39dac57259cff8b61db0b22cb2ad0a8adb02692e.tar UXP-39dac57259cff8b61db0b22cb2ad0a8adb02692e.tar.gz UXP-39dac57259cff8b61db0b22cb2ad0a8adb02692e.tar.lz UXP-39dac57259cff8b61db0b22cb2ad0a8adb02692e.tar.xz UXP-39dac57259cff8b61db0b22cb2ad0a8adb02692e.zip |
Merge branch 'redwood' into 28.9-platform
Diffstat (limited to 'layout/tables')
-rw-r--r-- | layout/tables/celldata.h | 6 | ||||
-rw-r--r-- | layout/tables/nsCellMap.cpp | 8 | ||||
-rw-r--r-- | layout/tables/nsITableCellLayout.h | 10 | ||||
-rw-r--r-- | layout/tables/nsTableCellFrame.cpp | 128 | ||||
-rw-r--r-- | layout/tables/nsTableCellFrame.h | 55 | ||||
-rw-r--r-- | layout/tables/nsTableFrame.cpp | 258 | ||||
-rw-r--r-- | layout/tables/nsTableFrame.h | 33 | ||||
-rw-r--r-- | layout/tables/nsTableRowFrame.cpp | 38 | ||||
-rw-r--r-- | layout/tables/nsTableRowFrame.h | 4 | ||||
-rw-r--r-- | layout/tables/nsTableRowGroupFrame.cpp | 6 |
10 files changed, 353 insertions, 193 deletions
diff --git a/layout/tables/celldata.h b/layout/tables/celldata.h index b744b5175..ac7be58d7 100644 --- a/layout/tables/celldata.h +++ b/layout/tables/celldata.h @@ -6,6 +6,7 @@ #define CellData_h__ #include "nsISupports.h" +#include "nsITableCellLayout.h" // for MAX_COLSPAN / MAX_ROWSPAN #include "nsCoord.h" #include "mozilla/gfx/Types.h" #include "mozilla/WritingModes.h" @@ -15,11 +16,6 @@ class nsTableCellFrame; class nsCellMap; class BCCellData; - -#define MAX_ROWSPAN 65534 // the cellmap can not handle more. -#define MAX_COLSPAN 1000 // limit as IE and opera do. If this ever changes, - // change COL_SPAN_OFFSET/COL_SPAN_SHIFT accordingly. - /** * Data stored by nsCellMap to rationalize rowspan and colspan cells. */ diff --git a/layout/tables/nsCellMap.cpp b/layout/tables/nsCellMap.cpp index bdd12cf70..4852a4bdd 100644 --- a/layout/tables/nsCellMap.cpp +++ b/layout/tables/nsCellMap.cpp @@ -2431,9 +2431,8 @@ void nsCellMap::Dump(bool aIsBorderCollapse) const if (cd) { if (cd->IsOrig()) { nsTableCellFrame* cellFrame = cd->GetCellFrame(); - int32_t cellFrameColIndex; - cellFrame->GetColIndex(cellFrameColIndex); - printf("C%d,%d=%p(%d) ", rIndex, colIndex, (void*)cellFrame, + uint32_t cellFrameColIndex = cellFrame->ColIndex(); + printf("C%d,%d=%p(%u) ", rIndex, colIndex, (void*)cellFrame, cellFrameColIndex); cellCount++; } @@ -2520,8 +2519,7 @@ nsCellMap::GetCellInfoAt(const nsTableCellMap& aMap, cellFrame = GetCellFrame(aRowX, aColX, *data, true); } if (cellFrame && aColSpan) { - int32_t initialColIndex; - cellFrame->GetColIndex(initialColIndex); + uint32_t initialColIndex = cellFrame->ColIndex(); *aColSpan = GetEffectiveColSpan(aMap, aRowX, initialColIndex); } } diff --git a/layout/tables/nsITableCellLayout.h b/layout/tables/nsITableCellLayout.h index e761d76be..fdf693b06 100644 --- a/layout/tables/nsITableCellLayout.h +++ b/layout/tables/nsITableCellLayout.h @@ -7,9 +7,14 @@ #include "nsQueryFrame.h" +#define MAX_ROWSPAN 65534 // the cellmap can not handle more. +#define MAX_COLSPAN 1000 // limit as IE and opera do. If this ever changes, +// change COL_SPAN_OFFSET/COL_SPAN_SHIFT accordingly. + /** * nsITableCellLayout * interface for layout objects that act like table cells. + * XXX: This interface should really go away... * * @author sclark */ @@ -22,11 +27,6 @@ public: /** return the mapped cell's row and column indexes (starting at 0 for each) */ NS_IMETHOD GetCellIndexes(int32_t &aRowIndex, int32_t &aColIndex)=0; - /** return the mapped cell's row index (starting at 0 for the first row) */ - virtual nsresult GetRowIndex(int32_t &aRowIndex) const = 0; - - /** return the mapped cell's column index (starting at 0 for the first column) */ - virtual nsresult GetColIndex(int32_t &aColIndex) const = 0; }; #endif diff --git a/layout/tables/nsTableCellFrame.cpp b/layout/tables/nsTableCellFrame.cpp index ec9458f76..8b811df1e 100644 --- a/layout/tables/nsTableCellFrame.cpp +++ b/layout/tables/nsTableCellFrame.cpp @@ -59,20 +59,6 @@ nsTableCellFrame::~nsTableCellFrame() NS_IMPL_FRAMEARENA_HELPERS(nsTableCellFrame) -nsTableCellFrame* -nsTableCellFrame::GetNextCell() const -{ - nsIFrame* childFrame = GetNextSibling(); - while (childFrame) { - nsTableCellFrame *cellFrame = do_QueryFrame(childFrame); - if (cellFrame) { - return cellFrame; - } - childFrame = childFrame->GetNextSibling(); - } - return nullptr; -} - void nsTableCellFrame::Init(nsIContent* aContent, nsContainerFrame* aParent, @@ -88,8 +74,7 @@ nsTableCellFrame::Init(nsIContent* aContent, if (aPrevInFlow) { // Set the column index nsTableCellFrame* cellFrame = (nsTableCellFrame*)aPrevInFlow; - int32_t colIndex; - cellFrame->GetColIndex(colIndex); + uint32_t colIndex = cellFrame->ColIndex(); SetColIndex(colIndex); } } @@ -183,34 +168,6 @@ nsTableCellFrame::NeedsToObserve(const ReflowInput& aReflowInput) } nsresult -nsTableCellFrame::GetRowIndex(int32_t &aRowIndex) const -{ - nsresult result; - nsTableRowFrame* row = static_cast<nsTableRowFrame*>(GetParent()); - if (row) { - aRowIndex = row->GetRowIndex(); - result = NS_OK; - } - else { - aRowIndex = 0; - result = NS_ERROR_NOT_INITIALIZED; - } - return result; -} - -nsresult -nsTableCellFrame::GetColIndex(int32_t &aColIndex) const -{ - if (GetPrevInFlow()) { - return static_cast<nsTableCellFrame*>(FirstInFlow())->GetColIndex(aColIndex); - } - else { - aColIndex = mColIndex; - return NS_OK; - } -} - -nsresult nsTableCellFrame::AttributeChanged(int32_t aNameSpaceID, nsIAtom* aAttribute, int32_t aModType) @@ -238,13 +195,13 @@ nsTableCellFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext) nsTableFrame* tableFrame = GetTableFrame(); if (tableFrame->IsBorderCollapse() && tableFrame->BCRecalcNeeded(aOldStyleContext, StyleContext())) { - int32_t colIndex, rowIndex; - GetColIndex(colIndex); - GetRowIndex(rowIndex); + uint32_t colIndex = ColIndex(); + uint32_t rowIndex = RowIndex(); // row span needs to be clamped as we do not create rows in the cellmap // which do not have cells originating in them TableArea damageArea(colIndex, rowIndex, GetColSpan(), - std::min(GetRowSpan(), tableFrame->GetRowCount() - rowIndex)); + std::min(static_cast<uint32_t>(GetRowSpan()), + tableFrame->GetRowCount() - rowIndex)); tableFrame->AddBCDamageArea(damageArea); } } @@ -464,19 +421,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) { @@ -501,7 +479,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()) { @@ -704,16 +682,18 @@ nsTableCellFrame::GetCellBaseline() const borderPadding; } -int32_t nsTableCellFrame::GetRowSpan() +int32_t +nsTableCellFrame::GetRowSpan() { int32_t rowSpan=1; - nsGenericHTMLElement *hc = nsGenericHTMLElement::FromContent(mContent); // Don't look at the content's rowspan if we're a pseudo cell - if (hc && !StyleContext()->GetPseudo()) { - const nsAttrValue* attr = hc->GetParsedAttr(nsGkAtoms::rowspan); + if (!StyleContext()->GetPseudo()) { + dom::Element* elem = mContent->AsElement(); + const nsAttrValue* attr = elem->GetParsedAttr(nsGkAtoms::rowspan); // Note that we don't need to check the tag name, because only table cells - // and table headers parse the "rowspan" attribute into an integer. + // (including MathML <mtd>) and table headers parse the "rowspan" attribute + // into an integer. if (attr && attr->Type() == nsAttrValue::eInteger) { rowSpan = attr->GetIntegerValue(); } @@ -721,16 +701,20 @@ int32_t nsTableCellFrame::GetRowSpan() return rowSpan; } -int32_t nsTableCellFrame::GetColSpan() +int32_t +nsTableCellFrame::GetColSpan() { int32_t colSpan=1; - nsGenericHTMLElement *hc = nsGenericHTMLElement::FromContent(mContent); // Don't look at the content's colspan if we're a pseudo cell - if (hc && !StyleContext()->GetPseudo()) { - const nsAttrValue* attr = hc->GetParsedAttr(nsGkAtoms::colspan); + if (!StyleContext()->GetPseudo()) { + dom::Element* elem = mContent->AsElement(); + const nsAttrValue* attr = elem->GetParsedAttr( + MOZ_UNLIKELY(elem->IsMathMLElement()) ? nsGkAtoms::columnspan_ + : nsGkAtoms::colspan); // Note that we don't need to check the tag name, because only table cells - // and table headers parse the "colspan" attribute into an integer. + // (including MathML <mtd>) and table headers parse the "colspan" attribute + // into an integer. if (attr && attr->Type() == nsAttrValue::eInteger) { colSpan = attr->GetIntegerValue(); } @@ -807,14 +791,13 @@ CalcUnpaginatedBSize(nsTableCellFrame& aCellFrame, nsTableRowGroupFrame* firstRGInFlow = static_cast<nsTableRowGroupFrame*>(row->GetParent()); - int32_t rowIndex; - firstCellInFlow->GetRowIndex(rowIndex); + uint32_t rowIndex = firstCellInFlow->RowIndex(); int32_t rowSpan = aTableFrame.GetEffectiveRowSpan(*firstCellInFlow); nscoord computedBSize = firstTableInFlow->GetRowSpacing(rowIndex, rowIndex + rowSpan - 1); computedBSize -= aBlockDirBorderPadding; - int32_t rowX; + uint32_t rowX; for (row = firstRGInFlow->GetFirstRow(), rowX = 0; row; row = row->GetNextRow(), rowX++) { if (rowX > rowIndex + rowSpan - 1) { break; @@ -1029,12 +1012,7 @@ nsTableCellFrame::AccessibleType() NS_IMETHODIMP nsTableCellFrame::GetCellIndexes(int32_t &aRowIndex, int32_t &aColIndex) { - nsresult res = GetRowIndex(aRowIndex); - if (NS_FAILED(res)) - { - aColIndex = 0; - return res; - } + aRowIndex = RowIndex(); aColIndex = mColIndex; return NS_OK; } diff --git a/layout/tables/nsTableCellFrame.h b/layout/tables/nsTableCellFrame.h index 5f87c5f6d..f626a45b0 100644 --- a/layout/tables/nsTableCellFrame.h +++ b/layout/tables/nsTableCellFrame.h @@ -165,11 +165,11 @@ public: /** * return the cell's specified row span. this is what was specified in the - * content model or in the style info, and is always >= 1. + * content model or in the style info, and is always >= 0. * to get the effective row span (the actual value that applies), use GetEffectiveRowSpan() * @see nsTableFrame::GetEffectiveRowSpan() */ - virtual int32_t GetRowSpan(); + int32_t GetRowSpan(); // there is no set row index because row index depends on the cell's parent row only @@ -183,7 +183,10 @@ public: NS_IMETHOD GetCellIndexes(int32_t &aRowIndex, int32_t &aColIndex) override; /** return the mapped cell's row index (starting at 0 for the first row) */ - virtual nsresult GetRowIndex(int32_t &aRowIndex) const override; + uint32_t RowIndex() const + { + return static_cast<nsTableRowFrame*>(GetParent())->GetRowIndex(); + } /** * return the cell's specified col span. this is what was specified in the @@ -191,10 +194,19 @@ public: * to get the effective col span (the actual value that applies), use GetEffectiveColSpan() * @see nsTableFrame::GetEffectiveColSpan() */ - virtual int32_t GetColSpan(); + int32_t GetColSpan(); /** return the cell's column index (starting at 0 for the first column) */ - virtual nsresult GetColIndex(int32_t &aColIndex) const override; + uint32_t ColIndex() const + { + // NOTE: We copy this from previous continuations, and we don't ever have + // dynamic updates when tables split, so our mColIndex always matches our + // first continuation's. + MOZ_ASSERT(static_cast<nsTableCellFrame*>(FirstContinuation())->mColIndex == + mColIndex, + "mColIndex out of sync with first continuation"); + return mColIndex; + } void SetColIndex(int32_t aColIndex); /** return the available isize given to this frame during its last reflow */ @@ -209,13 +221,23 @@ 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(); void SetHasPctOverBSize(bool aValue); - nsTableCellFrame* GetNextCell() const; + nsTableCellFrame* GetNextCell() const + { + nsIFrame* sibling = GetNextSibling(); +#ifdef DEBUG + if (sibling) { + nsTableCellFrame* cellFrame = do_QueryFrame(sibling); + MOZ_ASSERT(cellFrame, "How do we have a non-cell sibling?"); + } +#endif // DEBUG + return static_cast<nsTableCellFrame*>(sibling); + } virtual LogicalMargin GetBorderWidth(WritingMode aWM) const; @@ -237,6 +259,10 @@ public: 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 GetLogicalSkipSides(const ReflowInput* aReflowInput = nullptr) const override; @@ -273,7 +299,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); } @@ -350,4 +376,17 @@ private: BCPixelSize mIStartBorder; }; +// Implemented here because that's a sane-ish way to make the includes work out. +inline nsTableCellFrame* nsTableRowFrame::GetFirstCell() const +{ + nsIFrame* firstChild = mFrames.FirstChild(); +#ifdef DEBUG + if (firstChild) { + nsTableCellFrame* cellFrame = do_QueryFrame(firstChild); + MOZ_ASSERT(cellFrame, "How do we have a non-cell sibling?"); + } +#endif // DEBUG + return static_cast<nsTableCellFrame*>(firstChild); +} + #endif diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index 890d050fd..e5a48139a 100644 --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -368,9 +368,8 @@ nsTableFrame::AttributeChangedFor(nsIFrame* aFrame, nsTableCellMap* cellMap = GetCellMap(); if (cellMap) { // for now just remove the cell from the map and reinsert it - int32_t rowIndex, colIndex; - cellFrame->GetRowIndex(rowIndex); - cellFrame->GetColIndex(colIndex); + uint32_t rowIndex = cellFrame->RowIndex(); + uint32_t colIndex = cellFrame->ColIndex(); RemoveCell(cellFrame, rowIndex); AutoTArray<nsTableCellFrame*, 1> cells; cells.AppendElement(cellFrame); @@ -447,9 +446,7 @@ nsTableFrame::GetEffectiveRowSpan(int32_t aRowIndex, nsTableCellMap* cellMap = GetCellMap(); NS_PRECONDITION (nullptr != cellMap, "bad call, cellMap not yet allocated."); - int32_t colIndex; - aCell.GetColIndex(colIndex); - return cellMap->GetEffectiveRowSpan(aRowIndex, colIndex); + return cellMap->GetEffectiveRowSpan(aRowIndex, aCell.ColIndex()); } int32_t @@ -458,9 +455,8 @@ nsTableFrame::GetEffectiveRowSpan(const nsTableCellFrame& aCell, { nsTableCellMap* tableCellMap = GetCellMap(); if (!tableCellMap) ABORT1(1); - int32_t colIndex, rowIndex; - aCell.GetColIndex(colIndex); - aCell.GetRowIndex(rowIndex); + uint32_t colIndex = aCell.ColIndex(); + uint32_t rowIndex = aCell.RowIndex(); if (aCellMap) return aCellMap->GetRowSpan(rowIndex, colIndex, true); @@ -474,9 +470,8 @@ nsTableFrame::GetEffectiveColSpan(const nsTableCellFrame& aCell, { nsTableCellMap* tableCellMap = GetCellMap(); if (!tableCellMap) ABORT1(1); - int32_t colIndex, rowIndex; - aCell.GetColIndex(colIndex); - aCell.GetRowIndex(rowIndex); + uint32_t colIndex = aCell.ColIndex(); + uint32_t rowIndex = aCell.RowIndex(); if (aCellMap) return aCellMap->GetEffectiveColSpan(*tableCellMap, rowIndex, colIndex); @@ -1192,11 +1187,19 @@ 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, @@ -1209,10 +1212,14 @@ static void PaintRowGroupBackground(nsTableRowGroupFrame* aRowGroup, nsIFrame* aFrame, nsDisplayListBuilder* aBuilder, - const nsDisplayListSet& aLists) + const nsDisplayListSet& aLists, + const nsRect& aDirtyRect) { for (nsTableRowFrame* row = aRowGroup->GetFirstRow(); row; row = row->GetNextRow()) { - PaintRowBackground(row, aFrame, aBuilder, aLists, row->GetNormalPosition()); + if (!aDirtyRect.Intersects(nsRect(row->GetNormalPosition(), row->GetSize()))) { + continue; + } + PaintRowBackground(row, aFrame, aBuilder, aLists, aDirtyRect, row->GetNormalPosition()); } } @@ -1221,23 +1228,112 @@ PaintRowGroupBackgroundByColIdx(nsTableRowGroupFrame* aRowGroup, nsIFrame* aFrame, nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists, - const nsTArray<int32_t>& aColIdx, + 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()) { - int32_t curColIdx; - cell->GetColIndex(curColIdx); - if (aColIdx.Contains(curColIdx)) { - auto cellRect = cell->GetRectRelativeToSelf() + cell->GetNormalPosition() + row->GetNormalPosition() + aOffset; + + 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); + } + } +} + +static inline bool FrameHasBorder(nsIFrame* f) +{ + if (!f->StyleVisibility()->IsVisible()) { + return false; + } + + if (f->StyleBorder()->HasBorder()) { + return true; + } + + return false; +} + +void nsTableFrame::CalcHasBCBorders() +{ + if (!IsBorderCollapse()) { + SetHasBCBorders(false); + return; + } + + if (FrameHasBorder(this)) { + SetHasBCBorders(true); + return; + } + + // Check col and col group has borders. + for (nsIFrame* f : this->GetChildList(kColGroupList)) { + if (FrameHasBorder(f)) { + SetHasBCBorders(true); + return; + } + + nsTableColGroupFrame *colGroup = static_cast<nsTableColGroupFrame*>(f); + for (nsTableColFrame* col = colGroup->GetFirstColumn(); col; col = col->GetNextCol()) { + if (FrameHasBorder(col)) { + SetHasBCBorders(true); + return; } } } + + // check row group, row and cell has borders. + RowGroupArray rowGroups; + OrderRowGroups(rowGroups); + for (nsTableRowGroupFrame* rowGroup : rowGroups) { + if (FrameHasBorder(rowGroup)) { + SetHasBCBorders(true); + return; + } + + for (nsTableRowFrame* row = rowGroup->GetFirstRow(); row; row = row->GetNextRow()) { + if (FrameHasBorder(row)) { + SetHasBCBorders(true); + return; + } + + for (nsTableCellFrame* cell = row->GetFirstCell(); cell; cell = cell->GetNextCell()) { + if (FrameHasBorder(cell)) { + SetHasBCBorders(true); + return; + } + } + } + } + + SetHasBCBorders(false); } /* static */ void @@ -1247,66 +1343,94 @@ 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<nsTableRowGroupFrame*>(aFrame); - PaintRowGroupBackground(rowGroup, aFrame, aBuilder, aLists); - } else if (aFrame->GetType() == nsGkAtoms::tableRowFrame) { - nsTableRowFrame* row = static_cast<nsTableRowFrame*>(aFrame); - PaintRowBackground(row, aFrame, aBuilder, aLists); - } else if (aFrame->GetType() == nsGkAtoms::tableColGroupFrame) { - // Compute background rect by iterating all cell frame. - nsTableColGroupFrame* colGroup = static_cast<nsTableColGroupFrame*>(aFrame); - // Collecting column index. - AutoTArray<int32_t, 1> colIdx; - for (nsTableColFrame* col = colGroup->GetFirstColumn(); col; col = col->GetNextCol()) { - colIdx.AppendElement(col->GetColIndex()); - } + // 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(); - PaintRowGroupBackgroundByColIdx(rowGroup, aFrame, aBuilder, aLists, colIdx, offset); + 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<int32_t, 1> colIdx; - colIdx.AppendElement(col->GetColIndex()); + } + } 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()); - 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); + 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; } - } else { - nsDisplayBackgroundImage::AppendBackgroundItemsToTop(aBuilder, aFrame, - aFrame->GetRectRelativeToSelf(), - aLists.BorderBackground()); + PaintRowGroupBackgroundByColIdx(rowGroup, aFrame, aBuilder, aLists, aDirtyRect, colIdx, offset); } + } else if (isVisible) { + 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,16 +1438,21 @@ 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<nsTableFrame*>(aFrame); // In the collapsed border model, overlay all collapsed borders. if (table->IsBorderCollapse()) { - aLists.BorderBackground()->AppendNewToTop( - new (aBuilder) nsDisplayTableBorderCollapse(aBuilder, table)); + if (table->HasBCBorders()) { + aLists.BorderBackground()->AppendNewToTop( + new (aBuilder) nsDisplayTableBorderCollapse(aBuilder, table)); + } } else { - aLists.BorderBackground()->AppendNewToTop( - new (aBuilder) nsDisplayBorder(aBuilder, table)); + const nsStyleBorder* borderStyle = aFrame->StyleBorder(); + if (borderStyle->HasBorder()) { + aLists.BorderBackground()->AppendNewToTop( + new (aBuilder) nsDisplayBorder(aBuilder, table)); + } } } } @@ -3911,9 +4040,8 @@ nsTableFrame::DumpRowGroup(nsIFrame* aKidFrame) for (nsIFrame* childFrame : cFrame->PrincipalChildList()) { nsTableCellFrame *cellFrame = do_QueryFrame(childFrame); if (cellFrame) { - int32_t colIndex; - cellFrame->GetColIndex(colIndex); - printf("cell(%d)=%p ", colIndex, static_cast<void*>(childFrame)); + uint32_t colIndex = cellFrame->ColIndex(); + printf("cell(%u)=%p ", colIndex, static_cast<void*>(childFrame)); } } printf("\n"); @@ -4046,6 +4174,7 @@ nsTableFrame::AddBCDamageArea(const TableArea& aValue) #endif SetNeedToCalcBCBorders(true); + SetNeedToCalcHasBCBorders(true); // Get the property BCPropertyData* value = GetOrCreateBCProperty(); if (value) { @@ -4086,6 +4215,7 @@ 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 a6b786402..d739faa72 100644 --- a/layout/tables/nsTableFrame.h +++ b/layout/tables/nsTableFrame.h @@ -761,6 +761,13 @@ 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 @@ -870,6 +877,8 @@ 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 @@ -965,6 +974,30 @@ 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 ea2477b73..02b85a141 100644 --- a/layout/tables/nsTableRowFrame.cpp +++ b/layout/tables/nsTableRowFrame.cpp @@ -235,7 +235,7 @@ nsTableRowFrame::InsertFrames(ChildListID aListID, // insert the cells into the cell map int32_t colIndex = -1; if (prevCellFrame) { - prevCellFrame->GetColIndex(colIndex); + colIndex = prevCellFrame->ColIndex(); } tableFrame->InsertCells(cellChildren, GetRowIndex(), colIndex); @@ -304,18 +304,6 @@ GetBSizeOfRowsSpannedBelowFirst(nsTableCellFrame& aTableCellFrame, return bsize; } -nsTableCellFrame* -nsTableRowFrame::GetFirstCell() -{ - for (nsIFrame* childFrame : mFrames) { - nsTableCellFrame *cellFrame = do_QueryFrame(childFrame); - if (cellFrame) { - return cellFrame; - } - } - return nullptr; -} - /** * Post-reflow hook. This is where the table row does its post-processing */ @@ -659,8 +647,7 @@ CalcAvailISize(nsTableFrame& aTableFrame, nsTableCellFrame& aCellFrame) { nscoord cellAvailISize = 0; - int32_t colIndex; - aCellFrame.GetColIndex(colIndex); + uint32_t colIndex = aCellFrame.ColIndex(); int32_t colspan = aTableFrame.GetEffectiveColSpan(aCellFrame); NS_ASSERTION(colspan > 0, "effective colspan should be positive"); nsTableFrame* fifTable = @@ -799,12 +786,12 @@ nsTableRowFrame::ReflowChildren(nsPresContext* aPresContext, } } - int32_t cellColIndex; - cellFrame->GetColIndex(cellColIndex); + uint32_t cellColIndex = cellFrame->ColIndex(); cellColSpan = aTableFrame.GetEffectiveColSpan(*cellFrame); // If the adjacent cell is in a prior row (because of a rowspan) add in the space - if (prevColIndex != (cellColIndex - 1)) { + // NOTE: prevColIndex can be -1 here. + if (prevColIndex != (static_cast<int32_t>(cellColIndex) - 1)) { iCoord += GetSpaceBetween(prevColIndex, cellColIndex, cellColSpan, aTableFrame, false); } @@ -1172,8 +1159,7 @@ nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset, shift = rowRect.BSize(wm); nsTableCellFrame* cellFrame = GetFirstCell(); if (cellFrame) { - int32_t rowIndex; - cellFrame->GetRowIndex(rowIndex); + uint32_t rowIndex = cellFrame->RowIndex(); shift += tableFrame->GetRowSpacing(rowIndex); while (cellFrame) { LogicalRect cRect = cellFrame->GetLogicalRect(wm, containerSize); @@ -1204,13 +1190,13 @@ nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset, for (nsIFrame* kidFrame : mFrames) { nsTableCellFrame *cellFrame = do_QueryFrame(kidFrame); if (cellFrame) { - int32_t cellColIndex; - cellFrame->GetColIndex(cellColIndex); + uint32_t cellColIndex = cellFrame->ColIndex(); int32_t cellColSpan = tableFrame->GetEffectiveColSpan(*cellFrame); // If the adjacent cell is in a prior row (because of a rowspan) add in // the space - if (prevColIndex != (cellColIndex - 1)) { + // NOTE: prevColIndex can be -1 here. + if (prevColIndex != (static_cast<int32_t>(cellColIndex) - 1)) { iPos += GetSpaceBetween(prevColIndex, cellColIndex, cellColSpan, *tableFrame, true); } @@ -1323,9 +1309,9 @@ nsTableRowFrame::InsertCellFrame(nsTableCellFrame* aFrame, for (nsIFrame* child : mFrames) { nsTableCellFrame *cellFrame = do_QueryFrame(child); if (cellFrame) { - int32_t colIndex; - cellFrame->GetColIndex(colIndex); - if (colIndex < aColIndex) { + uint32_t colIndex = cellFrame->ColIndex(); + // Can aColIndex be -1 here? Let's assume it can for now. + if (static_cast<int32_t>(colIndex) < aColIndex) { priorCell = cellFrame; } else break; diff --git a/layout/tables/nsTableRowFrame.h b/layout/tables/nsTableRowFrame.h index 9e15d851f..c53c81ff1 100644 --- a/layout/tables/nsTableRowFrame.h +++ b/layout/tables/nsTableRowFrame.h @@ -82,7 +82,9 @@ public: const nsRect& aDirtyRect, const nsDisplayListSet& aLists) override; - nsTableCellFrame* GetFirstCell() ; + // 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; /** calls Reflow for all of its child cells. * Cells with rowspan=1 are all set to the same height and stacked horizontally. diff --git a/layout/tables/nsTableRowGroupFrame.cpp b/layout/tables/nsTableRowGroupFrame.cpp index f613c8b79..37f577f5c 100644 --- a/layout/tables/nsTableRowGroupFrame.cpp +++ b/layout/tables/nsTableRowGroupFrame.cpp @@ -137,8 +137,7 @@ nsTableRowGroupFrame::InitRepeatedFrame(nsTableRowGroupFrame* aHeaderFooterFrame while (copyCellFrame && originalCellFrame) { NS_ASSERTION(originalCellFrame->GetContent() == copyCellFrame->GetContent(), "cell frames have different content"); - int32_t colIndex; - originalCellFrame->GetColIndex(colIndex); + uint32_t colIndex = originalCellFrame->ColIndex(); copyCellFrame->SetColIndex(colIndex); // Move to the next cell frame @@ -998,8 +997,7 @@ nsTableRowGroupFrame::SplitSpanningCells(nsPresContext& aPresContext, nsTableCellFrame* contCell = static_cast<nsTableCellFrame*>( aPresContext.PresShell()->FrameConstructor()-> CreateContinuingFrame(&aPresContext, cell, &aLastRow)); - int32_t colIndex; - cell->GetColIndex(colIndex); + uint32_t colIndex = cell->ColIndex(); aContRow->InsertCellFrame(contCell, colIndex); } } |