Bug 1285874 - Maintain a map of removed table-rows and use it to lazily recalculate row indices
MozReview-Commit-ID: Jt6QJTp0YGe
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -911,16 +911,17 @@ nsTableFrame::InsertRows(nsTableRowGroup
printf("=== insertRowsBefore firstRow=%d \n", aRowIndex);
Dump(true, false, true);
#endif
int32_t numColsToAdd = 0;
nsTableCellMap* cellMap = GetCellMap();
if (cellMap) {
TableArea damageArea(0, 0, 0, 0);
+ RecalculateRowIndices();
int32_t origNumRows = cellMap->GetRowCount();
int32_t numNewRows = aRowFrames.Length();
cellMap->InsertRows(aRowGroupFrame, aRowFrames, aRowIndex, aConsiderSpans, damageArea);
MatchCellMapToColCache(cellMap);
if (aRowIndex < origNumRows) {
AdjustRowIndices(aRowIndex, numNewRows);
}
// assign the correct row indices to the new rows. If they were adjusted above
@@ -936,16 +937,96 @@ nsTableFrame::InsertRows(nsTableRowGroup
#ifdef DEBUG_TABLE_CELLMAP
printf("=== insertRowsAfter \n");
Dump(true, false, true);
#endif
return numColsToAdd;
}
+void
+nsTableFrame::RecalculateRowIndices()
+{
+ if (mDeletedRowIndexRanges.size() == 0)
+ return;
+
+ RowGroupArray rowGroups;
+ OrderRowGroups(rowGroups);
+
+ for (auto rowGroup : rowGroups) {
+ rowGroup->RecalculateRowIndices();
+ }
+
+ mDeletedRowIndexRanges.clear();
+}
+
+void
+nsTableFrame::AddDeletedRowIndex(int32_t aDeletedRowIndex)
+{
+ if (mDeletedRowIndexRanges.size() == 0) {
+ mDeletedRowIndexRanges.insert(std::pair<int32_t, int32_t>(aDeletedRowIndex,
+ aDeletedRowIndex));
+ return;
+ }
+
+ // find the position of the current deleted row index
+ // among the previous deleted row indices
+ // call to mDeletedRowIndexRanges.upper_bound is
+ // O(log(mDeletedRowIndexRanges.size()))
+ auto nextItr = mDeletedRowIndexRanges.upper_bound(aDeletedRowIndex);
+ auto prevItr = nextItr;
+ if (prevItr != mDeletedRowIndexRanges.begin())
+ prevItr--;
+
+ if ((prevItr->second == aDeletedRowIndex - 1) &&
+ (nextItr != mDeletedRowIndexRanges.end()) &&
+ (nextItr->first == aDeletedRowIndex + 1)) {
+ // merge previous and next ranges
+ prevItr->second = nextItr->second;
+ mDeletedRowIndexRanges.erase(nextItr);
+ } else if (prevItr->second == aDeletedRowIndex - 1) {
+ // include current deleted index in range above
+ prevItr->second++;
+ } else if ((nextItr != mDeletedRowIndexRanges.end()) &&
+ (nextItr->first == aDeletedRowIndex + 1)) {
+ // include current deleted index in range below
+ mDeletedRowIndexRanges.insert(std::pair<int32_t, int32_t>(aDeletedRowIndex,
+ nextItr->second));
+ mDeletedRowIndexRanges.erase(nextItr);
+ } else {
+ // add a new range
+ mDeletedRowIndexRanges.insert(std::pair<int32_t, int32_t>(aDeletedRowIndex,
+ aDeletedRowIndex));
+ }
+}
+
+int32_t
+nsTableFrame::GetAdjustmentForOriginalIndex(int32_t aOriginalIndex)
+{
+ if (mDeletedRowIndexRanges.size() == 0)
+ return 0;
+
+ int32_t adjustment = 0;
+
+ // O(log(mDeletedRowIndexRanges.size()))
+ auto itr = mDeletedRowIndexRanges.upper_bound(aOriginalIndex);
+
+ if (itr != mDeletedRowIndexRanges.begin())
+ itr--;
+
+ while (itr != mDeletedRowIndexRanges.begin()) {
+ adjustment += (itr->second - itr->first + 1);
+ itr--;
+ }
+
+ adjustment += (itr->second - itr->first + 1);
+
+ return adjustment;
+}
+
// this cannot extend beyond a single row group
void
nsTableFrame::RemoveRows(nsTableRowFrame& aFirstRowFrame,
int32_t aNumRowsToRemove,
bool aConsiderSpans)
{
#ifdef TBD_OPTIMIZATION
// decide if we need to rebalance. we have to do this here because the row group
@@ -966,23 +1047,27 @@ nsTableFrame::RemoveRows(nsTableRowFrame
int32_t firstRowIndex = aFirstRowFrame.GetRowIndex();
#ifdef DEBUG_TABLE_CELLMAP
printf("=== removeRowsBefore firstRow=%d numRows=%d\n", firstRowIndex, aNumRowsToRemove);
Dump(true, false, true);
#endif
nsTableCellMap* cellMap = GetCellMap();
if (cellMap) {
TableArea damageArea(0, 0, 0, 0);
+
+ // add this row's original index to list of deleted rows indices
+ aFirstRowFrame.AddDeletedRowIndex();
+
cellMap->RemoveRows(firstRowIndex, aNumRowsToRemove, aConsiderSpans, damageArea);
MatchCellMapToColCache(cellMap);
if (IsBorderCollapse()) {
AddBCDamageArea(damageArea);
}
}
- AdjustRowIndices(firstRowIndex, -aNumRowsToRemove);
+
#ifdef DEBUG_TABLE_CELLMAP
printf("=== removeRowsAfter\n");
Dump(true, true, true);
#endif
}
// collect the rows ancestors of aFrame
int32_t
--- a/layout/tables/nsTableFrame.h
+++ b/layout/tables/nsTableFrame.h
@@ -840,16 +840,33 @@ public: /* ----- Cell Map public methods
}
// return the last col index which isn't of type eColAnonymousCell
int32_t GetIndexOfLastRealCol();
/** returns true if table-layout:auto */
bool IsAutoLayout();
+public: /* ---------- Row index management methods ------------ */
+
+ /** add index of deleted row to mDeletedRowIndexRanges
+ * @param aDeletedRowIndex - index of row that was deleted
+ */
+ void AddDeletedRowIndex(int32_t aDeletedRowIndex);
+
+ /** calculate the amount that aOriginalIndex must be adjusted to get new index
+ * @param aOriginalIndex - The index that must be adjusted
+ */
+ int32_t GetAdjustmentForOriginalIndex(int32_t aOriginalIndex);
+
+ /** recalculate the row indices of all rows and overwrite
+ * the value of the original index with this calculated index
+ */
+ void RecalculateRowIndices();
+
public:
#ifdef DEBUG
void Dump(bool aDumpRows,
bool aDumpCols,
bool aDumpCellMap);
#endif
@@ -872,16 +889,18 @@ protected:
uint32_t mRowInserted:1;
uint32_t mNeedToCalcBCBorders:1;
uint32_t mGeometryDirty:1;
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?
} mBits;
+ std::map<int32_t, int32_t> mDeletedRowIndexRanges; // maintains ranges of row
+ // indices of deleted rows
nsTableCellMap* mCellMap; // maintains the relationships between rows, cols, and cells
nsITableLayoutStrategy* mTableLayoutStrategy;// the layout strategy for this frame
nsFrameList mColGroups; // the list of colgroup frames
};
inline bool nsTableFrame::IsRowGroup(mozilla::StyleDisplay aDisplayType) const
{
--- a/layout/tables/nsTableRowFrame.h
+++ b/layout/tables/nsTableRowFrame.h
@@ -138,23 +138,31 @@ public:
* 'vertical-align: baseline', *including* cells with rowspans.
* returns 0 if we don't have any cell with 'vertical-align: baseline'
*/
nscoord GetMaxCellAscent() const;
/* return the row ascent
*/
nscoord GetRowBaseline(mozilla::WritingMode aWritingMode);
-
+
/** returns the ordinal position of this row in its table */
virtual int32_t GetRowIndex() const;
/** set this row's starting row index */
void SetRowIndex (int aRowIndex);
+ /** returns a value that the originalIndex must be adjusted by to get the new index value */
+ int32_t GetAdjustmentForOriginalIndex(int32_t aOriginalIndex) const;
+
+ /** add a new index to data structure storing range of indices of deleted rows
+ * this also merges ranges if needed
+ */
+ void AddDeletedRowIndex();
+
/** used by row group frame code */
nscoord ReflowCellFrame(nsPresContext* aPresContext,
const ReflowInput& aReflowInput,
bool aIsTopOfPage,
nsTableCellFrame* aCellFrame,
nscoord aAvailableBSize,
nsReflowStatus& aStatus);
/**
@@ -317,19 +325,34 @@ private:
* Sets the NS_ROW_HAS_CELL_WITH_STYLE_BSIZE bit to indicate whether
* this row has any cells that have non-auto-bsize. (Row-spanning
* cells are ignored.)
*/
void InitHasCellWithStyleBSize(nsTableFrame* aTableFrame);
};
+inline int32_t
+nsTableRowFrame::GetAdjustmentForOriginalIndex(int32_t aOriginalIndex) const
+{
+ nsTableRowGroupFrame* parentFrame = GetTableRowGroupFrame();
+ return parentFrame->GetAdjustmentForOriginalIndex(aOriginalIndex);
+}
+
+inline void nsTableRowFrame::AddDeletedRowIndex()
+{
+ nsTableRowGroupFrame* parentFrame = GetTableRowGroupFrame();
+ parentFrame->AddDeletedRowIndex(int32_t(mBits.mRowIndex));
+}
+
inline int32_t nsTableRowFrame::GetRowIndex() const
{
- return int32_t(mBits.mRowIndex);
+ int32_t originalRowIndex = int32_t(mBits.mRowIndex);
+ int32_t rowIndexAdjustment = GetAdjustmentForOriginalIndex(originalRowIndex);
+ return (originalRowIndex - rowIndexAdjustment);
}
inline void nsTableRowFrame::SetRowIndex (int aRowIndex)
{
mBits.mRowIndex = aRowIndex;
}
inline bool nsTableRowFrame::IsFirstInserted() const
--- a/layout/tables/nsTableRowGroupFrame.cpp
+++ b/layout/tables/nsTableRowGroupFrame.cpp
@@ -115,16 +115,42 @@ void nsTableRowGroupFrame::AdjustRowInd
for (nsIFrame* rowFrame : mFrames) {
if (mozilla::StyleDisplay::TableRow == rowFrame->StyleDisplay()->mDisplay) {
int32_t index = ((nsTableRowFrame*)rowFrame)->GetRowIndex();
if (index >= aRowIndex)
((nsTableRowFrame *)rowFrame)->SetRowIndex(index+anAdjustment);
}
}
}
+
+int32_t
+nsTableRowGroupFrame::GetAdjustmentForOriginalIndex(int32_t aOriginalIndex)
+{
+ nsTableFrame* tableFrame = GetTableFrame();
+ return tableFrame->GetAdjustmentForOriginalIndex(aOriginalIndex);
+}
+
+void
+nsTableRowGroupFrame::AddDeletedRowIndex(int32_t aDeletedRowIndex)
+{
+ nsTableFrame* tableFrame = GetTableFrame();
+ return tableFrame->AddDeletedRowIndex(aDeletedRowIndex);
+}
+
+void
+nsTableRowGroupFrame::RecalculateRowIndices()
+{
+ for (nsIFrame* rowFrame : mFrames) {
+ if (mozilla::StyleDisplay::TableRow == rowFrame->StyleDisplay()->mDisplay) {
+ int32_t newIndex = ((nsTableRowFrame*)rowFrame)->GetRowIndex();
+ ((nsTableRowFrame*)rowFrame)->SetRowIndex(newIndex);
+ }
+ }
+}
+
nsresult
nsTableRowGroupFrame::InitRepeatedFrame(nsTableRowGroupFrame* aHeaderFooterFrame)
{
nsTableRowFrame* copyRowFrame = GetFirstRow();
nsTableRowFrame* originalRowFrame = aHeaderFooterFrame->GetFirstRow();
AddStateBits(NS_REPEATED_ROW_OR_ROWGROUP);
while (copyRowFrame && originalRowFrame) {
copyRowFrame->AddStateBits(NS_REPEATED_ROW_OR_ROWGROUP);
--- a/layout/tables/nsTableRowGroupFrame.h
+++ b/layout/tables/nsTableRowGroupFrame.h
@@ -121,16 +121,31 @@ public:
/** Adjust the row indices of all rows whose index is >= aRowIndex.
* @param aRowIndex - start adjusting with this index
* @param aAdjustment - shift the row index by this amount
*/
void AdjustRowIndices(int32_t aRowIndex,
int32_t anAdjustment);
+ /** return a value that the originalIndex must be adjusted by
+ * to get the new index value
+ */
+ int32_t GetAdjustmentForOriginalIndex(int32_t aOriginalIndex);
+
+ /** add a new index to data structure storing range of indices of deleted rows
+ * this also merges ranges if needed
+ */
+ void AddDeletedRowIndex(int32_t aDeletedRowIndex);
+
+ /** recalculate the row indices of all rows and overwrite
+ * the value of the original index with this calculated index
+ */
+ void RecalculateRowIndices();
+
/**
* Used for header and footer row group frames that are repeated when
* splitting a table frame.
*
* Performs any table specific initialization
*
* @param aHeaderFooterFrame the original header or footer row group frame
* that was repeated