Bug 1285874 - Maintain a map of removed table-rows and use it to lazily recalculate row indices draft
authorNeerja Pancholi <npancholi@mozilla.com>
Mon, 24 Oct 2016 21:56:41 -0700
changeset 435761 eb0bfe946282b711f3e752477f63236c1b3110b1
parent 428736 c845bfd0accb7e0c29b41713255963b08006e701
child 536378 4b5f5257e7efa46702ee57df740a670ad8f9eb6d
push id35121
push userbmo:npancholi@mozilla.com
push dateWed, 09 Nov 2016 06:22:13 +0000
bugs1285874
milestone52.0a1
Bug 1285874 - Maintain a map of removed table-rows and use it to lazily recalculate row indices MozReview-Commit-ID: Jt6QJTp0YGe
layout/tables/nsTableFrame.cpp
layout/tables/nsTableFrame.h
layout/tables/nsTableRowFrame.h
layout/tables/nsTableRowGroupFrame.cpp
layout/tables/nsTableRowGroupFrame.h
--- 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