forked from mirrors/gecko-dev
Bug 1285874 - Maintain a map of removed table-rows and use it to lazily recalculate row indices. r=dbaron
MozReview-Commit-ID: Jt6QJTp0YGe
This commit is contained in:
parent
bd0bfddf8e
commit
ee17cb9c09
5 changed files with 254 additions and 17 deletions
|
|
@ -916,19 +916,26 @@ nsTableFrame::InsertRows(nsTableRowGroupFrame* aRowGroupFrame,
|
|||
nsTableCellMap* cellMap = GetCellMap();
|
||||
if (cellMap) {
|
||||
TableArea damageArea(0, 0, 0, 0);
|
||||
bool didRecalculate = 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
|
||||
// it may not have been done correctly because each row is constructed with index 0
|
||||
for (int32_t rowB = 0; rowB < numNewRows; rowB++) {
|
||||
nsTableRowFrame* rowFrame = aRowFrames.ElementAt(rowB);
|
||||
rowFrame->SetRowIndex(aRowIndex + rowB);
|
||||
|
||||
if (!didRecalculate) {
|
||||
if (aRowIndex < origNumRows) {
|
||||
AdjustRowIndices(aRowIndex, numNewRows);
|
||||
}
|
||||
|
||||
// assign the correct row indices to the new rows. If they were recalculated
|
||||
// above it may not have been done correctly because each row is constructed
|
||||
// with index 0
|
||||
for (int32_t rowB = 0; rowB < numNewRows; rowB++) {
|
||||
nsTableRowFrame* rowFrame = aRowFrames.ElementAt(rowB);
|
||||
rowFrame->SetRowIndex(aRowIndex + rowB);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsBorderCollapse()) {
|
||||
AddBCDamageArea(damageArea);
|
||||
}
|
||||
|
|
@ -941,11 +948,111 @@ nsTableFrame::InsertRows(nsTableRowGroupFrame* aRowGroupFrame,
|
|||
return numColsToAdd;
|
||||
}
|
||||
|
||||
bool
|
||||
nsTableFrame::RecalculateRowIndices()
|
||||
{
|
||||
if (mDeletedRowIndexRanges.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
mDeletedRowIndexRanges.clear();
|
||||
|
||||
RowGroupArray rowGroups;
|
||||
OrderRowGroups(rowGroups);
|
||||
|
||||
int32_t rowIndex = 0;
|
||||
for (uint32_t rgIdx = 0; rgIdx < rowGroups.Length(); rgIdx++) {
|
||||
nsTableRowGroupFrame* rgFrame = rowGroups[rgIdx];
|
||||
const nsFrameList& rowFrames = rgFrame->PrincipalChildList();
|
||||
for (nsFrameList::Enumerator rEnum(rowFrames); !rEnum.AtEnd(); rEnum.Next()) {
|
||||
if (mozilla::StyleDisplay::TableRow == rEnum.get()->StyleDisplay()->mDisplay) {
|
||||
nsTableRowFrame *row = static_cast<nsTableRowFrame*>(rEnum.get());
|
||||
row->SetRowIndex(rowIndex);
|
||||
rowIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
nsTableFrame::AddDeletedRowIndex(int32_t aDeletedRowStoredIndex)
|
||||
{
|
||||
if (mDeletedRowIndexRanges.size() == 0) {
|
||||
mDeletedRowIndexRanges.insert(std::pair<int32_t, int32_t>
|
||||
(aDeletedRowStoredIndex,
|
||||
aDeletedRowStoredIndex));
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the position of the current deleted row's stored index
|
||||
// among the previous deleted row index ranges and merge ranges if
|
||||
// they are consecutive, else add a new (disjoint) range to the map.
|
||||
// Call to mDeletedRowIndexRanges.upper_bound is
|
||||
// O(log(mDeletedRowIndexRanges.size())) therefore call to
|
||||
// AddDeletedRowIndex is also ~O(log(mDeletedRowIndexRanges.size()))
|
||||
|
||||
// greaterIter = will point to smallest range in the map with lower value
|
||||
// greater than the aDeletedRowStoredIndex.
|
||||
// If no such value exists, point to end of map.
|
||||
// smallerIter = will point to largest range in the map with higher value
|
||||
// smaller than the aDeletedRowStoredIndex
|
||||
// If no such value exists, point to beginning of map.
|
||||
// i.e. when both values exist below is true:
|
||||
// smallerIter->second < aDeletedRowStoredIndex < greaterIter->first
|
||||
auto greaterIter = mDeletedRowIndexRanges.upper_bound(aDeletedRowStoredIndex);
|
||||
auto smallerIter = greaterIter;
|
||||
if (smallerIter != mDeletedRowIndexRanges.begin()) {
|
||||
smallerIter--;
|
||||
}
|
||||
|
||||
if (smallerIter->second == aDeletedRowStoredIndex - 1) {
|
||||
if (greaterIter != mDeletedRowIndexRanges.end() &&
|
||||
greaterIter->first == aDeletedRowStoredIndex + 1) {
|
||||
// merge current index with smaller and greater range as they are consecutive
|
||||
smallerIter->second = greaterIter->second;
|
||||
mDeletedRowIndexRanges.erase(greaterIter);
|
||||
}
|
||||
else {
|
||||
// add aDeletedRowStoredIndex in the smaller range as it is consecutive
|
||||
smallerIter->second = aDeletedRowStoredIndex;
|
||||
}
|
||||
} else if (greaterIter != mDeletedRowIndexRanges.end() &&
|
||||
greaterIter->first == aDeletedRowStoredIndex + 1) {
|
||||
// add aDeletedRowStoredIndex in the greater range as it is consecutive
|
||||
mDeletedRowIndexRanges.insert(std::pair<int32_t, int32_t>
|
||||
(aDeletedRowStoredIndex,
|
||||
greaterIter->second));
|
||||
mDeletedRowIndexRanges.erase(greaterIter);
|
||||
} else {
|
||||
// add new range as aDeletedRowStoredIndex is disjoint from existing ranges
|
||||
mDeletedRowIndexRanges.insert(std::pair<int32_t, int32_t>
|
||||
(aDeletedRowStoredIndex,
|
||||
aDeletedRowStoredIndex));
|
||||
}
|
||||
}
|
||||
|
||||
int32_t
|
||||
nsTableFrame::GetAdjustmentForStoredIndex(int32_t aStoredIndex)
|
||||
{
|
||||
if (mDeletedRowIndexRanges.size() == 0)
|
||||
return 0;
|
||||
|
||||
int32_t adjustment = 0;
|
||||
|
||||
// O(log(mDeletedRowIndexRanges.size()))
|
||||
auto endIter = mDeletedRowIndexRanges.upper_bound(aStoredIndex);
|
||||
for (auto iter = mDeletedRowIndexRanges.begin(); iter != endIter; ++iter) {
|
||||
adjustment += iter->second - iter->first + 1;
|
||||
}
|
||||
|
||||
return adjustment;
|
||||
}
|
||||
|
||||
// this cannot extend beyond a single row group
|
||||
void
|
||||
nsTableFrame::RemoveRows(nsTableRowFrame& aFirstRowFrame,
|
||||
int32_t aNumRowsToRemove,
|
||||
bool aConsiderSpans)
|
||||
int32_t aNumRowsToRemove,
|
||||
bool aConsiderSpans)
|
||||
{
|
||||
#ifdef TBD_OPTIMIZATION
|
||||
// decide if we need to rebalance. we have to do this here because the row group
|
||||
|
|
@ -971,13 +1078,19 @@ nsTableFrame::RemoveRows(nsTableRowFrame& aFirstRowFrame,
|
|||
nsTableCellMap* cellMap = GetCellMap();
|
||||
if (cellMap) {
|
||||
TableArea damageArea(0, 0, 0, 0);
|
||||
|
||||
// Mark rows starting from aFirstRowFrame to the next 'aNumRowsToRemove-1'
|
||||
// number of rows as deleted.
|
||||
nsTableRowGroupFrame* parentFrame = aFirstRowFrame.GetTableRowGroupFrame();
|
||||
parentFrame->MarkRowsAsDeleted(aFirstRowFrame, aNumRowsToRemove);
|
||||
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -780,10 +780,10 @@ public:
|
|||
nsTableCellMap* GetCellMap() const;
|
||||
|
||||
/** Iterate over the row groups and 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
|
||||
*/
|
||||
* 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 aAdjustment);
|
||||
|
||||
|
|
@ -842,6 +842,43 @@ public: /* ----- Cell Map public methods ----- */
|
|||
/** returns true if table-layout:auto */
|
||||
bool IsAutoLayout();
|
||||
|
||||
public:
|
||||
|
||||
/* ---------- Row index management methods ------------ */
|
||||
|
||||
/** Add the given index to the existing ranges of
|
||||
* deleted row indices and merge ranges if, with the addition of the new
|
||||
* index, they become consecutive.
|
||||
* @param aDeletedRowStoredIndex - index of the row that was deleted
|
||||
* Note - 'stored' index here refers to the index that was assigned to
|
||||
* the row before any remove row operations were performed i.e. the
|
||||
* value of mRowIndex and not the value returned by GetRowIndex()
|
||||
*/
|
||||
void AddDeletedRowIndex(int32_t aDeletedRowStoredIndex);
|
||||
|
||||
/** Calculate the change that aStoredIndex must be increased/decreased by
|
||||
* to get new index.
|
||||
* Note that aStoredIndex is always the index of an undeleted row (since
|
||||
* rows that have already been deleted can never call this method).
|
||||
* @param aStoredIndex - The stored index value that must be adjusted
|
||||
* Note - 'stored' index here refers to the index that was assigned to
|
||||
* the row before any remove row operations were performed i.e. the
|
||||
* value of mRowIndex and not the value returned by GetRowIndex()
|
||||
*/
|
||||
int32_t GetAdjustmentForStoredIndex(int32_t aStoredIndex);
|
||||
|
||||
/** Recalculate the row indices of all rows (if needed) and overwrite
|
||||
* the value of the stored index with this newly calculated index.
|
||||
* Returns whether recalculation was performed.
|
||||
*/
|
||||
bool RecalculateRowIndices();
|
||||
|
||||
/** Returns whether mDeletedRowIndexRanges is empty
|
||||
*/
|
||||
bool IsDeletedRowIndexRangesEmpty() const {
|
||||
return mDeletedRowIndexRanges.empty();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
#ifdef DEBUG
|
||||
|
|
@ -874,6 +911,8 @@ protected:
|
|||
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
|
||||
|
|
|
|||
|
|
@ -140,13 +140,19 @@ public:
|
|||
/* 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);
|
||||
|
||||
// See nsTableFrame.h
|
||||
int32_t GetAdjustmentForStoredIndex(int32_t aStoredIndex) const;
|
||||
|
||||
// See nsTableFrame.h
|
||||
void AddDeletedRowIndex();
|
||||
|
||||
/** used by row group frame code */
|
||||
nscoord ReflowCellFrame(nsPresContext* aPresContext,
|
||||
const ReflowInput& aReflowInput,
|
||||
|
|
@ -319,13 +325,34 @@ private:
|
|||
|
||||
};
|
||||
|
||||
inline int32_t
|
||||
nsTableRowFrame::GetAdjustmentForStoredIndex(int32_t aStoredIndex) const
|
||||
{
|
||||
nsTableRowGroupFrame* parentFrame = GetTableRowGroupFrame();
|
||||
return parentFrame->GetAdjustmentForStoredIndex(aStoredIndex);
|
||||
}
|
||||
|
||||
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 storedRowIndex = int32_t(mBits.mRowIndex);
|
||||
int32_t rowIndexAdjustment = GetAdjustmentForStoredIndex(storedRowIndex);
|
||||
return (storedRowIndex - rowIndexAdjustment);
|
||||
}
|
||||
|
||||
inline void nsTableRowFrame::SetRowIndex (int aRowIndex)
|
||||
{
|
||||
// Note: Setting the index of a row (as in the case of adding new rows) should
|
||||
// be preceded by a call to nsTableFrame::RecalculateRowIndices()
|
||||
// so as to correctly clear mDeletedRowIndexRanges.
|
||||
MOZ_ASSERT(GetTableRowGroupFrame()->
|
||||
GetTableFrame()->IsDeletedRowIndexRangesEmpty(),
|
||||
"mDeletedRowIndexRanges should be empty here!");
|
||||
mBits.mRowIndex = aRowIndex;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -120,6 +120,51 @@ void nsTableRowGroupFrame::AdjustRowIndices(int32_t aRowIndex,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32_t
|
||||
nsTableRowGroupFrame::GetAdjustmentForStoredIndex(int32_t aStoredIndex)
|
||||
{
|
||||
nsTableFrame* tableFrame = GetTableFrame();
|
||||
return tableFrame->GetAdjustmentForStoredIndex(aStoredIndex);
|
||||
}
|
||||
|
||||
void
|
||||
nsTableRowGroupFrame::MarkRowsAsDeleted(nsTableRowFrame& aStartRowFrame,
|
||||
int32_t aNumRowsToDelete)
|
||||
{
|
||||
nsTableRowFrame* currentRowFrame = &aStartRowFrame;
|
||||
for (;;) {
|
||||
// XXXneerja - Instead of calling AddDeletedRowIndex() per row frame
|
||||
// it is possible to change AddDeleteRowIndex to instead take
|
||||
// <start row index> and <num of rows to mark for deletion> as arguments.
|
||||
// The problem that emerges here is mDeletedRowIndexRanges only stores
|
||||
// disjoint index ranges and since AddDeletedRowIndex() must operate on
|
||||
// the "stored" index, in some cases it is possible that the range
|
||||
// of indices to delete becomes overlapping EG: Deleting rows 9 - 11 and
|
||||
// then from the remaining rows deleting the *new* rows 7 to 20.
|
||||
// Handling these overlapping ranges is much more complicated to
|
||||
// implement and so I opted to add the deleted row index of one row at a
|
||||
// time and maintain the invariant that the range of deleted row indices
|
||||
// is always disjoint.
|
||||
currentRowFrame->AddDeletedRowIndex();
|
||||
if (--aNumRowsToDelete == 0) {
|
||||
break;
|
||||
}
|
||||
currentRowFrame = do_QueryFrame(currentRowFrame->GetNextSibling());
|
||||
if (!currentRowFrame) {
|
||||
MOZ_ASSERT_UNREACHABLE("expected another row frame");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsTableRowGroupFrame::AddDeletedRowIndex(int32_t aDeletedRowStoredIndex)
|
||||
{
|
||||
nsTableFrame* tableFrame = GetTableFrame();
|
||||
return tableFrame->AddDeletedRowIndex(aDeletedRowStoredIndex);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTableRowGroupFrame::InitRepeatedFrame(nsTableRowGroupFrame* aHeaderFooterFrame)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -135,6 +135,19 @@ public:
|
|||
void AdjustRowIndices(int32_t aRowIndex,
|
||||
int32_t anAdjustment);
|
||||
|
||||
// See nsTableFrame.h
|
||||
int32_t GetAdjustmentForStoredIndex(int32_t aStoredIndex);
|
||||
|
||||
/* mark rows starting from aStartRowFrame to the next 'aNumRowsToRemove-1'
|
||||
* number of rows as deleted
|
||||
*/
|
||||
void MarkRowsAsDeleted(nsTableRowFrame& aStartRowFrame,
|
||||
int32_t aNumRowsToDelete);
|
||||
|
||||
// See nsTableFrame.h
|
||||
void AddDeletedRowIndex(int32_t aDeletedRowStoredIndex);
|
||||
|
||||
|
||||
/**
|
||||
* Used for header and footer row group frames that are repeated when
|
||||
* splitting a table frame.
|
||||
|
|
|
|||
Loading…
Reference in a new issue