Bug 1869043 allow a device to be specified with MediaTrackGraph::NotifyWhenDeviceStar...
[gecko.git] / layout / tables / nsCellMap.h
blob20bec0d07d6d6e9f72a0fbd98190272744175a9e
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #ifndef nsCellMap_h__
6 #define nsCellMap_h__
8 #include "nscore.h"
9 #include "celldata.h"
10 #include "nsTArray.h"
11 #include "nsCOMPtr.h"
12 #include "nsAlgorithm.h"
13 #include "nsRect.h"
14 #include <algorithm>
15 #include "TableArea.h"
17 #undef DEBUG_TABLE_CELLMAP
19 class nsTableCellFrame;
20 class nsTableRowFrame;
21 class nsTableRowGroupFrame;
22 class nsTableFrame;
23 class nsCellMap;
24 class nsPresContext;
25 class nsCellMapColumnIterator;
27 struct nsColInfo {
28 int32_t mNumCellsOrig; // number of cells originating in the col
29 int32_t mNumCellsSpan; // number of cells spanning into the col via colspans
30 // (not rowspans)
32 nsColInfo();
33 nsColInfo(int32_t aNumCellsOrig, int32_t aNumCellsSpan);
36 struct BCInfo {
37 nsTArray<BCData> mIEndBorders;
38 nsTArray<BCData> mBEndBorders;
39 BCData mBEndIEndCorner;
42 class nsTableCellMap {
43 typedef mozilla::TableArea TableArea;
45 public:
46 nsTableCellMap(nsTableFrame& aTableFrame, bool aBorderCollapse);
48 /** destructor
49 * NOT VIRTUAL BECAUSE THIS CLASS SHOULD **NEVER** BE SUBCLASSED
51 ~nsTableCellMap();
53 void RemoveGroupCellMap(nsTableRowGroupFrame* aRowGroup);
55 void InsertGroupCellMap(nsTableRowGroupFrame* aNewRowGroup,
56 nsTableRowGroupFrame*& aPrevRowGroup);
58 /**
59 * Get the nsCellMap for the given row group. If aStartHint is non-null,
60 * will start looking with that cellmap and only fall back to starting at the
61 * beginning of the list if that doesn't find us the right nsCellMap.
62 * Otherwise, just start at the beginning.
64 * aRowGroup must not be null.
66 nsCellMap* GetMapFor(const nsTableRowGroupFrame* aRowGroup,
67 nsCellMap* aStartHint) const;
69 /** synchronize the cellmaps with the rowgroups again **/
70 void Synchronize(nsTableFrame* aTableFrame);
72 nsTableCellFrame* GetCellFrame(int32_t aRowIndex, int32_t aColIndex,
73 CellData& aData, bool aUseRowIfOverlap) const;
75 /** return the CellData for the cell at (aRowIndex, aColIndex) */
76 CellData* GetDataAt(int32_t aRowIndex, int32_t aColIndex) const;
78 // this function creates a col if needed
79 nsColInfo* GetColInfoAt(int32_t aColIndex);
81 /** append the cellFrame at the end of the row at aRowIndex and return the col
82 * index
84 CellData* AppendCell(nsTableCellFrame& aCellFrame, int32_t aRowIndex,
85 bool aRebuildIfNecessary, TableArea& aDamageArea);
87 void InsertCells(nsTArray<nsTableCellFrame*>& aCellFrames, int32_t aRowIndex,
88 int32_t aColIndexBefore, TableArea& aDamageArea);
90 void RemoveCell(nsTableCellFrame* aCellFrame, int32_t aRowIndex,
91 TableArea& aDamageArea);
92 /** Remove the previously gathered column information */
93 void ClearCols();
94 void InsertRows(nsTableRowGroupFrame* aRowGroup,
95 nsTArray<nsTableRowFrame*>& aRows, int32_t aFirstRowIndex,
96 bool aConsiderSpans, TableArea& aDamageArea);
98 void RemoveRows(int32_t aFirstRowIndex, int32_t aNumRowsToRemove,
99 bool aConsiderSpans, TableArea& aDamageArea);
101 int32_t GetNumCellsOriginatingInRow(int32_t aRowIndex) const;
102 int32_t GetNumCellsOriginatingInCol(int32_t aColIndex) const;
104 /** indicate whether the row has more than one cell that either originates
105 * or is spanned from the rows above
107 bool HasMoreThanOneCell(int32_t aRowIndex) const;
109 int32_t GetEffectiveRowSpan(int32_t aRowIndex, int32_t aColIndex) const;
110 int32_t GetEffectiveColSpan(int32_t aRowIndex, int32_t aColIndex) const;
112 /** return the total number of columns in the table represented by this
113 * CellMap */
114 int32_t GetColCount() const;
116 /** return the actual number of rows in the table represented by this CellMap
118 int32_t GetRowCount() const;
120 nsTableCellFrame* GetCellInfoAt(int32_t aRowX, int32_t aColX,
121 bool* aOriginates = nullptr,
122 int32_t* aColSpan = nullptr) const;
125 * Returns the index at the given row and column coordinates.
127 * @see nsITableLayout::GetIndexByRowAndColumn()
129 * @param aRow [in] the row coordinate
130 * @param aColumn [in] the column coordinate
131 * @returns the index for the cell
133 int32_t GetIndexByRowAndColumn(int32_t aRow, int32_t aColumn) const;
136 * Retrieves the row and column coordinates for the given index.
138 * @see nsITableLayout::GetRowAndColumnByIndex()
140 * @param aIndex [in] the index for which coordinates are to be retrieved
141 * @param aRow [out] the row coordinate to be returned
142 * @param aColumn [out] the column coordinate to be returned
144 void GetRowAndColumnByIndex(int32_t aIndex, int32_t* aRow,
145 int32_t* aColumn) const;
147 void AddColsAtEnd(uint32_t aNumCols);
148 void RemoveColsAtEnd();
150 bool RowIsSpannedInto(int32_t aRowIndex, int32_t aNumEffCols) const;
151 bool RowHasSpanningCells(int32_t aRowIndex, int32_t aNumEffCols) const;
152 void RebuildConsideringCells(nsCellMap* aCellMap,
153 nsTArray<nsTableCellFrame*>* aCellFrames,
154 int32_t aRowIndex, int32_t aColIndex,
155 bool aInsert, TableArea& aDamageArea);
157 protected:
159 * Rebuild due to rows being inserted or deleted with cells spanning
160 * into or out of the rows. This function can only handle insertion
161 * or deletion but NOT both. So either aRowsToInsert must be null
162 * or aNumRowsToRemove must be 0.
164 * // XXXbz are both allowed to happen? That'd be a no-op...
166 void RebuildConsideringRows(nsCellMap* aCellMap, int32_t aStartRowIndex,
167 nsTArray<nsTableRowFrame*>* aRowsToInsert,
168 int32_t aNumRowsToRemove, TableArea& aDamageArea);
170 public:
171 void ResetBStartStart(mozilla::LogicalSide aSide, nsCellMap& aCellMap,
172 uint32_t aRowGroupStart, uint32_t aYPos,
173 uint32_t aXPos);
175 void SetBCBorderEdge(mozilla::LogicalSide aEdge, nsCellMap& aCellMap,
176 uint32_t aCellMapStart, uint32_t aYPos, uint32_t aXPos,
177 uint32_t aLength, BCBorderOwner aOwner, nscoord aSize,
178 bool aChanged);
180 void SetBCBorderCorner(mozilla::LogicalCorner aCorner, nsCellMap& aCellMap,
181 uint32_t aCellMapStart, uint32_t aYPos, uint32_t aXPos,
182 mozilla::LogicalSide aOwner, nscoord aSubSize,
183 bool aBevel, bool aIsBottomRight = false);
185 /** dump a representation of the cell map to stdout for debugging */
186 #ifdef DEBUG
187 void Dump(char* aString = nullptr) const;
188 #endif
190 protected:
191 BCData* GetIEndMostBorder(int32_t aRowIndex);
192 BCData* GetBEndMostBorder(int32_t aColIndex);
194 friend class nsCellMap;
195 friend class BCMapCellIterator;
196 friend class BCPaintBorderIterator;
197 friend class nsCellMapColumnIterator;
199 /** Insert a row group cellmap after aPrevMap, if aPrefMap is null insert it
200 * at the beginning, the ordering of the cellmap corresponds to the ordering
201 * of rowgroups once OrderRowGroups has been called
203 void InsertGroupCellMap(nsCellMap* aPrevMap, nsCellMap& aNewMap);
204 void DeleteIEndBEndBorders();
206 nsTableFrame& mTableFrame;
207 AutoTArray<nsColInfo, 8> mCols;
208 nsCellMap* mFirstMap;
209 // border collapsing info
210 BCInfo* mBCInfo;
213 /** nsCellMap is a support class for nsTablePart.
214 * It maintains an Rows x Columns grid onto which the cells of the table are
215 * mapped. This makes processing of rowspan and colspan attributes much easier.
216 * Each cell is represented by a CellData object.
218 * @see CellData
219 * @see nsTableFrame::AddCellToMap
220 * @see nsTableFrame::GrowCellMap
221 * @see nsTableFrame::BuildCellIntoMap
223 * mRows is an array of rows. Each row is an array of cells. a cell
224 * can be null.
226 class nsCellMap {
227 typedef mozilla::TableArea TableArea;
229 public:
230 /** constructor
231 * @param aRowGroupFrame the row group frame this is a cellmap for
232 * @param aIsBC whether the table is doing border-collapse
234 nsCellMap(nsTableRowGroupFrame* aRowGroupFrame, bool aIsBC);
236 /** destructor
237 * NOT VIRTUAL BECAUSE THIS CLASS SHOULD **NEVER** BE SUBCLASSED
239 ~nsCellMap();
241 static void Init();
242 static void Shutdown();
244 nsCellMap* GetNextSibling() const;
245 void SetNextSibling(nsCellMap* aSibling);
247 nsTableRowGroupFrame* GetRowGroup() const;
249 nsTableCellFrame* GetCellFrame(int32_t aRowIndex, int32_t aColIndex,
250 CellData& aData,
251 bool aUseRowSpanIfOverlap) const;
254 * Returns highest cell index within the cell map.
256 * @param aColCount [in] the number of columns in the table
258 int32_t GetHighestIndex(int32_t aColCount);
261 * Returns the index of the given row and column coordinates.
263 * @see nsITableLayout::GetIndexByRowAndColumn()
265 * @param aColCount [in] the number of columns in the table
266 * @param aRow [in] the row coordinate
267 * @param aColumn [in] the column coordinate
269 int32_t GetIndexByRowAndColumn(int32_t aColCount, int32_t aRow,
270 int32_t aColumn) const;
273 * Get the row and column coordinates at the given index.
275 * @see nsITableLayout::GetRowAndColumnByIndex()
277 * @param aColCount [in] the number of columns in the table
278 * @param aIndex [in] the index for which coordinates are to be retrieved
279 * @param aRow [out] the row coordinate to be returned
280 * @param aColumn [out] the column coordinate to be returned
282 void GetRowAndColumnByIndex(int32_t aColCount, int32_t aIndex, int32_t* aRow,
283 int32_t* aColumn) const;
285 /** append the cellFrame at an empty or dead cell or finally at the end of
286 * the row at aRowIndex and return a pointer to the celldata entry in the
287 * cellmap
289 * @param aMap - reference to the table cell map
290 * @param aCellFrame - a pointer to the cellframe which will be
291 * appended to the row
292 * @param aRowIndex - to this row the celldata entry will be added
293 * @param aRebuildIfNecessay - if a cell spans into a row below it might be
294 * necesserary to rebuild the cellmap as this
295 * rowspan might overlap another cell.
296 * @param aDamageArea - area in cellmap coordinates which have been
297 * updated.
298 * @param aColToBeginSearch - if not null contains the column number where
299 * the search for a empty or dead cell in the
300 * row should start
301 * @return - a pointer to the celldata entry inserted into
302 * the cellmap
304 CellData* AppendCell(nsTableCellMap& aMap, nsTableCellFrame* aCellFrame,
305 int32_t aRowIndex, bool aRebuildIfNecessary,
306 int32_t aRgFirstRowIndex, TableArea& aDamageArea,
307 int32_t* aBeginSearchAtCol = nullptr);
309 void InsertCells(nsTableCellMap& aMap,
310 nsTArray<nsTableCellFrame*>& aCellFrames, int32_t aRowIndex,
311 int32_t aColIndexBefore, int32_t aRgFirstRowIndex,
312 TableArea& aDamageArea);
314 void RemoveCell(nsTableCellMap& aMap, nsTableCellFrame* aCellFrame,
315 int32_t aRowIndex, int32_t aRgFirstRowIndex,
316 TableArea& aDamageArea);
318 void InsertRows(nsTableCellMap& aMap, nsTArray<nsTableRowFrame*>& aRows,
319 int32_t aFirstRowIndex, bool aConsiderSpans,
320 int32_t aRgFirstRowIndex, TableArea& aDamageArea);
322 void RemoveRows(nsTableCellMap& aMap, int32_t aFirstRowIndex,
323 int32_t aNumRowsToRemove, bool aConsiderSpans,
324 int32_t aRgFirstRowIndex, TableArea& aDamageArea);
326 int32_t GetNumCellsOriginatingInRow(int32_t aRowIndex) const;
327 int32_t GetNumCellsOriginatingInCol(int32_t aColIndex) const;
329 /** return the number of rows in the table represented by this CellMap */
330 int32_t GetRowCount(bool aConsiderDeadRowSpanRows = false) const;
332 nsTableCellFrame* GetCellInfoAt(const nsTableCellMap& aMap, int32_t aRowX,
333 int32_t aColX, bool* aOriginates = nullptr,
334 int32_t* aColSpan = nullptr) const;
336 bool RowIsSpannedInto(int32_t aRowIndex, int32_t aNumEffCols) const;
338 bool RowHasSpanningCells(int32_t aRowIndex, int32_t aNumEffCols) const;
340 /** indicate whether the row has more than one cell that either originates
341 * or is spanned from the rows above
343 bool HasMoreThanOneCell(int32_t aRowIndex) const;
345 /* Get the rowspan for a cell starting at aRowIndex and aColIndex.
346 * If aGetEffective is true the size will not exceed the last content based
347 * row. Cells can have a specified rowspan that extends below the last
348 * content based row. This is legitimate considering incr. reflow where the
349 * content rows will arive later.
351 int32_t GetRowSpan(int32_t aRowIndex, int32_t aColIndex,
352 bool aGetEffective) const;
354 int32_t GetEffectiveColSpan(const nsTableCellMap& aMap, int32_t aRowIndex,
355 int32_t aColIndex) const;
357 typedef nsTArray<CellData*> CellDataArray;
359 /** dump a representation of the cell map to stdout for debugging */
360 #ifdef DEBUG
361 void Dump(bool aIsBorderCollapse) const;
362 #endif
364 protected:
365 friend class nsTableCellMap;
366 friend class BCMapCellIterator;
367 friend class BCPaintBorderIterator;
368 friend class nsTableFrame;
369 friend class nsCellMapColumnIterator;
372 * Increase the number of rows in this cellmap by aNumRows. Put the
373 * new rows at aRowIndex. If aRowIndex is -1, put them at the end.
375 bool Grow(nsTableCellMap& aMap, int32_t aNumRows, int32_t aRowIndex = -1);
377 void GrowRow(CellDataArray& aRow, int32_t aNumCols);
379 /** assign aCellData to the cell at (aRow,aColumn) */
380 void SetDataAt(nsTableCellMap& aMap, CellData& aCellData,
381 int32_t aMapRowIndex, int32_t aColIndex);
383 CellData* GetDataAt(int32_t aMapRowIndex, int32_t aColIndex) const;
385 int32_t GetNumCellsIn(int32_t aColIndex) const;
387 void ExpandWithRows(nsTableCellMap& aMap,
388 nsTArray<nsTableRowFrame*>& aRowFrames,
389 int32_t aStartRowIndex, int32_t aRgFirstRowIndex,
390 TableArea& aDamageArea);
392 void ExpandWithCells(nsTableCellMap& aMap,
393 nsTArray<nsTableCellFrame*>& aCellFrames,
394 int32_t aRowIndex, int32_t aColIndex, int32_t aRowSpan,
395 bool aRowSpanIsZero, int32_t aRgFirstRowIndex,
396 TableArea& aDamageArea);
398 void ShrinkWithoutRows(nsTableCellMap& aMap, int32_t aFirstRowIndex,
399 int32_t aNumRowsToRemove, int32_t aRgFirstRowIndex,
400 TableArea& aDamageArea);
402 void ShrinkWithoutCell(nsTableCellMap& aMap, nsTableCellFrame& aCellFrame,
403 int32_t aRowIndex, int32_t aColIndex,
404 int32_t aRgFirstRowIndex, TableArea& aDamageArea);
407 * Rebuild due to rows being inserted or deleted with cells spanning
408 * into or out of the rows. This function can only handle insertion
409 * or deletion but NOT both. So either aRowsToInsert must be null
410 * or aNumRowsToRemove must be 0.
412 * // XXXbz are both allowed to happen? That'd be a no-op...
414 void RebuildConsideringRows(nsTableCellMap& aMap, int32_t aStartRowIndex,
415 nsTArray<nsTableRowFrame*>* aRowsToInsert,
416 int32_t aNumRowsToRemove);
418 void RebuildConsideringCells(nsTableCellMap& aMap, int32_t aNumOrigCols,
419 nsTArray<nsTableCellFrame*>* aCellFrames,
420 int32_t aRowIndex, int32_t aColIndex,
421 bool aInsert);
423 bool CellsSpanOut(nsTArray<nsTableRowFrame*>& aNewRows) const;
425 /** If a cell spans out of the area defined by aStartRowIndex, aEndRowIndex
426 * and aStartColIndex, aEndColIndex the cellmap changes are more severe so
427 * the corresponding routines needs to be called. This is also necessary if
428 * cells outside spans into this region.
429 * @aStartRowIndex - y start index
430 * @aEndRowIndex - y end index
431 * @param aStartColIndex - x start index
432 * @param aEndColIndex - x end index
433 * @return - true if a cell span crosses the border of the
434 region
436 bool CellsSpanInOrOut(int32_t aStartRowIndex, int32_t aEndRowIndex,
437 int32_t aStartColIndex, int32_t aEndColIndex) const;
439 bool CreateEmptyRow(int32_t aRowIndex, int32_t aNumCols);
441 int32_t GetRowSpanForNewCell(nsTableCellFrame* aCellFrameToAdd,
442 int32_t aRowIndex, bool& aIsZeroRowSpan) const;
444 // Destroy a CellData struct. This will handle the case of aData
445 // actually being a BCCellData properly.
446 void DestroyCellData(CellData* aData);
447 // Allocate a CellData struct. This will handle needing to create a
448 // BCCellData properly.
449 // @param aOrigCell the originating cell to pass to the celldata constructor
450 CellData* AllocCellData(nsTableCellFrame* aOrigCell);
452 /** an array containing, for each row, the CellDatas for the cells
453 * in that row. It can be larger than mContentRowCount due to row spans
454 * extending beyond the table */
455 // XXXbz once we have auto TArrays, we should probably use them here.
456 nsTArray<CellDataArray> mRows;
458 /** the number of rows in the table (content) which is not indentical to the
459 * number of rows in the cell map due to row spans extending beyond the end
460 * of thetable (dead rows) or empty tr tags
462 int32_t mContentRowCount;
464 // the row group that corresponds to this map
465 nsTableRowGroupFrame* mRowGroupFrame;
467 // the next row group cell map
468 nsCellMap* mNextSibling;
470 // Whether this is a BC cellmap or not
471 bool mIsBC;
473 // Prescontext to deallocate and allocate celldata
474 RefPtr<nsPresContext> mPresContext;
478 * A class for iterating the cells in a given column. Must be given a
479 * non-null nsTableCellMap and a column number valid for that cellmap.
481 class nsCellMapColumnIterator {
482 public:
483 nsCellMapColumnIterator(const nsTableCellMap* aMap, int32_t aCol)
484 : mMap(aMap),
485 mCurMap(aMap->mFirstMap),
486 mCurMapStart(0),
487 mCurMapRow(0),
488 mCol(aCol),
489 mFoundCells(0),
490 mCurMapContentRowCount(0),
491 mCurMapRelevantRowCount(0) {
492 MOZ_ASSERT(aMap, "Must have map");
493 MOZ_ASSERT(mCol < aMap->GetColCount(), "Invalid column");
494 mOrigCells = aMap->GetNumCellsOriginatingInCol(mCol);
495 if (mCurMap) {
496 mCurMapContentRowCount = mCurMap->GetRowCount();
497 uint32_t rowArrayLength = mCurMap->mRows.Length();
498 mCurMapRelevantRowCount =
499 std::min(mCurMapContentRowCount, rowArrayLength);
500 if (mCurMapRelevantRowCount == 0 && mOrigCells > 0) {
501 // This row group is useless; advance!
502 AdvanceRowGroup();
505 #ifdef DEBUG
506 else {
507 NS_ASSERTION(mOrigCells == 0, "Why no rowgroups?");
509 #endif
512 nsTableCellFrame* GetNextFrame(int32_t* aRow, int32_t* aColSpan);
514 private:
515 void AdvanceRowGroup();
517 // Advance the row; aIncrement is considered to be a cell's rowspan,
518 // so if 0 is passed in we'll advance to the next rowgroup.
519 void IncrementRow(int32_t aIncrement);
521 const nsTableCellMap* mMap;
522 const nsCellMap* mCurMap;
524 // mCurMapStart is the row in the entire nsTableCellMap where
525 // mCurMap starts. This is used to compute row indices to pass to
526 // nsTableCellMap::GetDataAt, so must be a _content_ row index.
527 uint32_t mCurMapStart;
529 // In steady-state mCurMapRow is the row in our current nsCellMap
530 // that we'll use the next time GetNextFrame() is called. Due to
531 // the way we skip over rowspans, the entry in mCurMapRow and mCol
532 // is either null, dead, originating, or a colspan. In particular,
533 // it cannot be a rowspan or overlap entry.
534 uint32_t mCurMapRow;
535 const int32_t mCol;
536 uint32_t mOrigCells;
537 uint32_t mFoundCells;
539 // The number of content rows in mCurMap. This may be bigger than the number
540 // of "relevant" rows, or it might be smaller.
541 uint32_t mCurMapContentRowCount;
543 // The number of "relevant" rows in mCurMap. That is, the number of rows
544 // which might have an originating cell in them. Once mCurMapRow reaches
545 // mCurMapRelevantRowCount, we should move to the next map.
546 uint32_t mCurMapRelevantRowCount;
549 /* ----- inline methods ----- */
550 inline int32_t nsTableCellMap::GetColCount() const { return mCols.Length(); }
552 inline nsCellMap* nsCellMap::GetNextSibling() const { return mNextSibling; }
554 inline void nsCellMap::SetNextSibling(nsCellMap* aSibling) {
555 mNextSibling = aSibling;
558 inline nsTableRowGroupFrame* nsCellMap::GetRowGroup() const {
559 return mRowGroupFrame;
562 inline int32_t nsCellMap::GetRowCount(bool aConsiderDeadRowSpanRows) const {
563 int32_t rowCount =
564 (aConsiderDeadRowSpanRows) ? mRows.Length() : mContentRowCount;
565 return rowCount;
568 // nsColInfo
570 inline nsColInfo::nsColInfo() : mNumCellsOrig(0), mNumCellsSpan(0) {}
572 inline nsColInfo::nsColInfo(int32_t aNumCellsOrig, int32_t aNumCellsSpan)
573 : mNumCellsOrig(aNumCellsOrig), mNumCellsSpan(aNumCellsSpan) {}
575 #endif