1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
39 #include "nsCellMap.h"
40 #include "nsTableFrame.h"
41 #include "nsTableCellFrame.h"
42 #include "nsTableRowGroupFrame.h"
44 // Empty static array used for SafeElementAt() calls on mRows.
45 static nsCellMap::CellDataArray
* sEmptyRow
;
49 CellData::CellData(nsTableCellFrame
* aOrigCell
)
51 MOZ_COUNT_CTOR(CellData
);
52 mOrigCell
= aOrigCell
;
57 MOZ_COUNT_DTOR(CellData
);
60 BCCellData::BCCellData(nsTableCellFrame
* aOrigCell
)
63 MOZ_COUNT_CTOR(BCCellData
);
66 BCCellData::~BCCellData()
68 MOZ_COUNT_DTOR(BCCellData
);
73 nsTableCellMap::nsTableCellMap(nsTableFrame
& aTableFrame
,
74 PRBool aBorderCollapse
)
75 :mTableFrame(aTableFrame
), mFirstMap(nsnull
), mBCInfo(nsnull
)
77 MOZ_COUNT_CTOR(nsTableCellMap
);
79 nsTableFrame::RowGroupArray orderedRowGroups
;
80 aTableFrame
.OrderRowGroups(orderedRowGroups
);
82 nsTableRowGroupFrame
* prior
= nsnull
;
83 for (PRUint32 rgX
= 0; rgX
< orderedRowGroups
.Length(); rgX
++) {
84 nsTableRowGroupFrame
* rgFrame
= orderedRowGroups
[rgX
];
85 InsertGroupCellMap(*rgFrame
, prior
);
88 if (aBorderCollapse
) {
89 mBCInfo
= new BCInfo();
93 nsTableCellMap::~nsTableCellMap()
95 MOZ_COUNT_DTOR(nsTableCellMap
);
97 nsCellMap
* cellMap
= mFirstMap
;
99 nsCellMap
* next
= cellMap
->GetNextSibling();
105 DeleteRightBottomBorders();
110 // Get the bcData holding the border segments of the right edge of the table
112 nsTableCellMap::GetRightMostBorder(PRInt32 aRowIndex
)
114 if (!mBCInfo
) ABORT1(nsnull
);
116 PRInt32 numRows
= mBCInfo
->mRightBorders
.Length();
117 if (aRowIndex
< numRows
) {
118 return &mBCInfo
->mRightBorders
.ElementAt(aRowIndex
);
121 if (!mBCInfo
->mRightBorders
.SetLength(aRowIndex
+1))
123 return &mBCInfo
->mRightBorders
.ElementAt(aRowIndex
);
126 // Get the bcData holding the border segments of the bottom edge of the table
128 nsTableCellMap::GetBottomMostBorder(PRInt32 aColIndex
)
130 if (!mBCInfo
) ABORT1(nsnull
);
132 PRInt32 numCols
= mBCInfo
->mBottomBorders
.Length();
133 if (aColIndex
< numCols
) {
134 return &mBCInfo
->mBottomBorders
.ElementAt(aColIndex
);
137 if (!mBCInfo
->mBottomBorders
.SetLength(aColIndex
+1))
139 return &mBCInfo
->mBottomBorders
.ElementAt(aColIndex
);
142 // delete the borders corresponding to the right and bottom edges of the table
144 nsTableCellMap::DeleteRightBottomBorders()
147 mBCInfo
->mBottomBorders
.Clear();
148 mBCInfo
->mRightBorders
.Clear();
153 nsTableCellMap::InsertGroupCellMap(nsCellMap
* aPrevMap
,
158 next
= aPrevMap
->GetNextSibling();
159 aPrevMap
->SetNextSibling(&aNewMap
);
163 mFirstMap
= &aNewMap
;
165 aNewMap
.SetNextSibling(next
);
168 void nsTableCellMap::InsertGroupCellMap(nsTableRowGroupFrame
& aNewGroup
,
169 nsTableRowGroupFrame
*& aPrevGroup
)
171 nsCellMap
* newMap
= new nsCellMap(aNewGroup
, mBCInfo
!= nsnull
);
173 nsCellMap
* prevMap
= nsnull
;
174 nsCellMap
* lastMap
= mFirstMap
;
176 nsCellMap
* map
= mFirstMap
;
179 if (map
->GetRowGroup() == aPrevGroup
) {
183 map
= map
->GetNextSibling();
189 aPrevGroup
= (prevMap
) ? prevMap
->GetRowGroup() : nsnull
;
195 InsertGroupCellMap(prevMap
, *newMap
);
199 void nsTableCellMap::RemoveGroupCellMap(nsTableRowGroupFrame
* aGroup
)
201 nsCellMap
* map
= mFirstMap
;
202 nsCellMap
* prior
= nsnull
;
204 if (map
->GetRowGroup() == aGroup
) {
205 nsCellMap
* next
= map
->GetNextSibling();
206 if (mFirstMap
== map
) {
210 prior
->SetNextSibling(next
);
216 map
= map
->GetNextSibling();
221 FindMapFor(const nsTableRowGroupFrame
* aRowGroup
,
223 const nsCellMap
* aEnd
)
225 for (nsCellMap
* map
= aStart
; map
!= aEnd
; map
= map
->GetNextSibling()) {
226 if (aRowGroup
== map
->GetRowGroup()) {
235 nsTableCellMap::GetMapFor(const nsTableRowGroupFrame
* aRowGroup
,
236 nsCellMap
* aStartHint
) const
238 NS_PRECONDITION(aRowGroup
, "Must have a rowgroup");
239 NS_ASSERTION(!aRowGroup
->GetPrevInFlow(), "GetMapFor called with continuation");
241 nsCellMap
* map
= FindMapFor(aRowGroup
, aStartHint
, nsnull
);
247 nsCellMap
* map
= FindMapFor(aRowGroup
, mFirstMap
, aStartHint
);
252 // if aRowGroup is a repeated header or footer find the header or footer it was repeated from
253 if (aRowGroup
->IsRepeatable()) {
254 nsTableFrame
* fifTable
= static_cast<nsTableFrame
*>(mTableFrame
.GetFirstInFlow());
256 const nsStyleDisplay
* display
= aRowGroup
->GetStyleDisplay();
257 nsTableRowGroupFrame
* rgOrig
=
258 (NS_STYLE_DISPLAY_TABLE_HEADER_GROUP
== display
->mDisplay
) ?
259 fifTable
->GetTHead() : fifTable
->GetTFoot();
260 // find the row group cell map using the original header/footer
261 if (rgOrig
&& rgOrig
!= aRowGroup
) {
262 return GetMapFor(rgOrig
, aStartHint
);
270 nsTableCellMap::Synchronize(nsTableFrame
* aTableFrame
)
272 nsTableFrame::RowGroupArray orderedRowGroups
;
273 nsAutoTPtrArray
<nsCellMap
, 8> maps
;
275 aTableFrame
->OrderRowGroups(orderedRowGroups
);
276 if (!orderedRowGroups
.Length()) {
280 // XXXbz this fails if orderedRowGroups is missing some row groups
281 // (due to OOM when appending to the array, e.g. -- we leak maps in
284 // Scope |map| outside the loop so we can use it as a hint.
285 nsCellMap
* map
= nsnull
;
286 for (PRUint32 rgX
= 0; rgX
< orderedRowGroups
.Length(); rgX
++) {
287 nsTableRowGroupFrame
* rgFrame
= orderedRowGroups
[rgX
];
288 map
= GetMapFor((nsTableRowGroupFrame
*)rgFrame
->GetFirstInFlow(), map
);
290 if (!maps
.AppendElement(map
)) {
293 NS_WARNING("Could not AppendElement");
299 PRInt32 mapIndex
= maps
.Length() - 1; // Might end up -1
300 nsCellMap
* nextMap
= maps
.ElementAt(mapIndex
);
301 nextMap
->SetNextSibling(nsnull
);
302 for (mapIndex
-- ; mapIndex
>= 0; mapIndex
--) {
303 nsCellMap
* map
= maps
.ElementAt(mapIndex
);
304 map
->SetNextSibling(nextMap
);
311 nsTableCellMap::HasMoreThanOneCell(PRInt32 aRowIndex
) const
313 PRInt32 rowIndex
= aRowIndex
;
314 nsCellMap
* map
= mFirstMap
;
316 if (map
->GetRowCount() > rowIndex
) {
317 return map
->HasMoreThanOneCell(rowIndex
);
319 rowIndex
-= map
->GetRowCount();
320 map
= map
->GetNextSibling();
326 nsTableCellMap::GetNumCellsOriginatingInRow(PRInt32 aRowIndex
) const
328 PRInt32 rowIndex
= aRowIndex
;
329 nsCellMap
* map
= mFirstMap
;
331 if (map
->GetRowCount() > rowIndex
) {
332 return map
->GetNumCellsOriginatingInRow(rowIndex
);
334 rowIndex
-= map
->GetRowCount();
335 map
= map
->GetNextSibling();
340 nsTableCellMap::GetEffectiveRowSpan(PRInt32 aRowIndex
,
341 PRInt32 aColIndex
) const
343 PRInt32 rowIndex
= aRowIndex
;
344 nsCellMap
* map
= mFirstMap
;
346 if (map
->GetRowCount() > rowIndex
) {
347 return map
->GetRowSpan(rowIndex
, aColIndex
, PR_TRUE
);
349 rowIndex
-= map
->GetRowCount();
350 map
= map
->GetNextSibling();
352 NS_NOTREACHED("Bogus row index?");
357 nsTableCellMap::GetEffectiveColSpan(PRInt32 aRowIndex
,
358 PRInt32 aColIndex
) const
360 PRInt32 rowIndex
= aRowIndex
;
361 nsCellMap
* map
= mFirstMap
;
363 if (map
->GetRowCount() > rowIndex
) {
365 return map
->GetEffectiveColSpan(*this, rowIndex
, aColIndex
, zeroColSpan
);
367 rowIndex
-= map
->GetRowCount();
368 map
= map
->GetNextSibling();
370 NS_NOTREACHED("Bogus row index?");
375 nsTableCellMap::GetCellFrame(PRInt32 aRowIndex
,
378 PRBool aUseRowIfOverlap
) const
380 PRInt32 rowIndex
= aRowIndex
;
381 nsCellMap
* map
= mFirstMap
;
383 if (map
->GetRowCount() > rowIndex
) {
384 return map
->GetCellFrame(rowIndex
, aColIndex
, aData
, aUseRowIfOverlap
);
386 rowIndex
-= map
->GetRowCount();
387 map
= map
->GetNextSibling();
393 nsTableCellMap::GetColInfoAt(PRInt32 aColIndex
)
395 PRInt32 numColsToAdd
= aColIndex
+ 1 - mCols
.Length();
396 if (numColsToAdd
> 0) {
397 AddColsAtEnd(numColsToAdd
); // XXX this could fail to add cols in theory
399 return &mCols
.ElementAt(aColIndex
);
403 nsTableCellMap::GetRowCount() const
406 nsCellMap
* map
= mFirstMap
;
408 numRows
+= map
->GetRowCount();
409 map
= map
->GetNextSibling();
415 nsTableCellMap::GetDataAt(PRInt32 aRowIndex
,
416 PRInt32 aColIndex
) const
418 PRInt32 rowIndex
= aRowIndex
;
419 nsCellMap
* map
= mFirstMap
;
421 if (map
->GetRowCount() > rowIndex
) {
422 return map
->GetDataAt(rowIndex
, aColIndex
);
424 rowIndex
-= map
->GetRowCount();
425 map
= map
->GetNextSibling();
431 nsTableCellMap::AddColsAtEnd(PRUint32 aNumCols
)
433 if (!mCols
.AppendElements(aNumCols
)) {
434 NS_WARNING("Could not AppendElement");
437 if (!mBCInfo
->mBottomBorders
.AppendElements(aNumCols
)) {
438 NS_WARNING("Could not AppendElement");
444 nsTableCellMap::RemoveColsAtEnd()
446 // Remove the cols at the end which don't have originating cells or cells spanning
447 // into them. Only do this if the col was created as eColAnonymousCell
448 PRInt32 numCols
= GetColCount();
449 PRInt32 lastGoodColIndex
= mTableFrame
.GetIndexOfLastRealCol();
450 for (PRInt32 colX
= numCols
- 1; (colX
>= 0) && (colX
> lastGoodColIndex
); colX
--) {
451 nsColInfo
& colInfo
= mCols
.ElementAt(colX
);
452 if ((colInfo
.mNumCellsOrig
<= 0) && (colInfo
.mNumCellsSpan
<= 0)) {
453 mCols
.RemoveElementAt(colX
);
456 PRInt32 count
= mBCInfo
->mBottomBorders
.Length();
458 mBCInfo
->mBottomBorders
.RemoveElementAt(colX
);
462 else break; // only remove until we encounter the 1st valid one
467 nsTableCellMap::ClearCols()
471 mBCInfo
->mBottomBorders
.Clear();
474 nsTableCellMap::InsertRows(nsTableRowGroupFrame
& aParent
,
475 nsTArray
<nsTableRowFrame
*>& aRows
,
476 PRInt32 aFirstRowIndex
,
477 PRBool aConsiderSpans
,
480 PRInt32 numNewRows
= aRows
.Length();
481 if ((numNewRows
<= 0) || (aFirstRowIndex
< 0)) ABORT0();
483 PRInt32 rowIndex
= aFirstRowIndex
;
484 nsCellMap
* cellMap
= mFirstMap
;
486 nsTableRowGroupFrame
* rg
= cellMap
->GetRowGroup();
487 if (rg
== &aParent
) {
488 cellMap
->InsertRows(*this, aRows
, rowIndex
, aConsiderSpans
, aDamageArea
);
489 aDamageArea
.y
= NS_MIN(aFirstRowIndex
, aDamageArea
.y
);
490 aDamageArea
.height
= NS_MAX(0, GetRowCount() - aDamageArea
.y
);
491 #ifdef DEBUG_TABLE_CELLMAP
492 Dump("after InsertRows");
495 PRInt32 count
= mBCInfo
->mRightBorders
.Length();
496 if (aFirstRowIndex
< count
) {
497 for (PRInt32 rowX
= aFirstRowIndex
; rowX
< aFirstRowIndex
+ numNewRows
; rowX
++) {
498 if (!mBCInfo
->mRightBorders
.InsertElementAt(rowX
))
503 GetRightMostBorder(aFirstRowIndex
); // this will create missing entries
504 for (PRInt32 rowX
= aFirstRowIndex
+ 1; rowX
< aFirstRowIndex
+ numNewRows
; rowX
++) {
505 if (!mBCInfo
->mRightBorders
.AppendElement())
512 rowIndex
-= cellMap
->GetRowCount();
513 cellMap
= cellMap
->GetNextSibling();
516 NS_ERROR("Attempt to insert row into wrong map.");
520 nsTableCellMap::RemoveRows(PRInt32 aFirstRowIndex
,
521 PRInt32 aNumRowsToRemove
,
522 PRBool aConsiderSpans
,
525 PRInt32 rowIndex
= aFirstRowIndex
;
526 nsCellMap
* cellMap
= mFirstMap
;
528 if (cellMap
->GetRowCount() > rowIndex
) {
529 cellMap
->RemoveRows(*this, rowIndex
, aNumRowsToRemove
, aConsiderSpans
, aDamageArea
);
530 nsTableRowGroupFrame
* rg
= cellMap
->GetRowGroup();
531 aDamageArea
.y
+= (rg
) ? rg
->GetStartRowIndex() : 0;
532 aDamageArea
.height
= NS_MAX(0, GetRowCount() - aFirstRowIndex
);
534 for (PRInt32 rowX
= aFirstRowIndex
+ aNumRowsToRemove
- 1; rowX
>= aFirstRowIndex
; rowX
--) {
535 if (PRUint32(rowX
) < mBCInfo
->mRightBorders
.Length()) {
536 mBCInfo
->mRightBorders
.RemoveElementAt(rowX
);
542 rowIndex
-= cellMap
->GetRowCount();
543 cellMap
= cellMap
->GetNextSibling();
545 #ifdef DEBUG_TABLE_CELLMAP
546 Dump("after RemoveRows");
553 nsTableCellMap::AppendCell(nsTableCellFrame
& aCellFrame
,
555 PRBool aRebuildIfNecessary
,
558 NS_ASSERTION(&aCellFrame
== aCellFrame
.GetFirstInFlow(), "invalid call on continuing frame");
559 nsIFrame
* rgFrame
= aCellFrame
.GetParent(); // get the row
560 if (!rgFrame
) return 0;
561 rgFrame
= rgFrame
->GetParent(); // get the row group
562 if (!rgFrame
) return 0;
564 CellData
* result
= nsnull
;
565 PRInt32 rowIndex
= aRowIndex
;
566 nsCellMap
* cellMap
= mFirstMap
;
568 if (cellMap
->GetRowGroup() == rgFrame
) {
569 result
= cellMap
->AppendCell(*this, &aCellFrame
, rowIndex
, aRebuildIfNecessary
, aDamageArea
);
570 nsTableRowGroupFrame
* rg
= cellMap
->GetRowGroup();
571 aDamageArea
.y
+= (rg
) ? rg
->GetStartRowIndex() : 0;
574 rowIndex
-= cellMap
->GetRowCount();
575 cellMap
= cellMap
->GetNextSibling();
577 #ifdef DEBUG_TABLE_CELLMAP
578 Dump("after AppendCell");
585 nsTableCellMap::InsertCells(nsTArray
<nsTableCellFrame
*>& aCellFrames
,
587 PRInt32 aColIndexBefore
,
590 PRInt32 rowIndex
= aRowIndex
;
591 nsCellMap
* cellMap
= mFirstMap
;
593 if (cellMap
->GetRowCount() > rowIndex
) {
594 cellMap
->InsertCells(*this, aCellFrames
, rowIndex
, aColIndexBefore
, aDamageArea
);
595 nsTableRowGroupFrame
* rg
= cellMap
->GetRowGroup();
596 aDamageArea
.y
+= (rg
) ? rg
->GetStartRowIndex() : 0;
597 aDamageArea
.width
= NS_MAX(0, GetColCount() - aColIndexBefore
- 1);
600 rowIndex
-= cellMap
->GetRowCount();
601 cellMap
= cellMap
->GetNextSibling();
603 #ifdef DEBUG_TABLE_CELLMAP
604 Dump("after InsertCells");
610 nsTableCellMap::RemoveCell(nsTableCellFrame
* aCellFrame
,
614 if (!aCellFrame
) ABORT0();
615 NS_ASSERTION(aCellFrame
== (nsTableCellFrame
*)aCellFrame
->GetFirstInFlow(),
616 "invalid call on continuing frame");
617 PRInt32 rowIndex
= aRowIndex
;
618 nsCellMap
* cellMap
= mFirstMap
;
620 if (cellMap
->GetRowCount() > rowIndex
) {
621 cellMap
->RemoveCell(*this, aCellFrame
, rowIndex
, aDamageArea
);
622 nsTableRowGroupFrame
* rg
= cellMap
->GetRowGroup();
623 aDamageArea
.y
+= (rg
) ? rg
->GetStartRowIndex() : 0;
625 aCellFrame
->GetColIndex(colIndex
);
626 aDamageArea
.width
= NS_MAX(0, GetColCount() - colIndex
- 1);
627 #ifdef DEBUG_TABLE_CELLMAP
628 Dump("after RemoveCell");
632 rowIndex
-= cellMap
->GetRowCount();
633 cellMap
= cellMap
->GetNextSibling();
635 // if we reach this point - the cell did not get removed, the caller of this routine
636 // will delete the cell and the cellmap will probably hold a reference to
637 // the deleted cell which will cause a subsequent crash when this cell is
639 NS_ERROR("nsTableCellMap::RemoveCell - could not remove cell");
643 SetDamageArea(PRInt32 aXOrigin
,
649 aDamageArea
.x
= aXOrigin
;
650 aDamageArea
.y
= aYOrigin
;
651 aDamageArea
.width
= NS_MAX(1, aWidth
);
652 aDamageArea
.height
= NS_MAX(1, aHeight
);
656 nsTableCellMap::RebuildConsideringCells(nsCellMap
* aCellMap
,
657 nsTArray
<nsTableCellFrame
*>* aCellFrames
,
663 PRInt32 numOrigCols
= GetColCount();
665 nsCellMap
* cellMap
= mFirstMap
;
666 PRInt32 rowCount
= 0;
668 if (cellMap
== aCellMap
) {
669 cellMap
->RebuildConsideringCells(*this, numOrigCols
, aCellFrames
, aRowIndex
, aColIndex
, aInsert
, aDamageArea
);
673 cellMap
->RebuildConsideringCells(*this, numOrigCols
, nsnull
, -1, 0, PR_FALSE
, aDamageArea
);
675 rowCount
+= cellMap
->GetRowCount();
676 cellMap
= cellMap
->GetNextSibling();
678 SetDamageArea(0, 0, GetColCount(), rowCount
, aDamageArea
);
682 nsTableCellMap::RebuildConsideringRows(nsCellMap
* aCellMap
,
683 PRInt32 aStartRowIndex
,
684 nsTArray
<nsTableRowFrame
*>* aRowsToInsert
,
685 PRInt32 aNumRowsToRemove
,
688 NS_PRECONDITION(!aRowsToInsert
|| aNumRowsToRemove
== 0,
689 "Can't handle both removing and inserting rows at once");
691 PRInt32 numOrigCols
= GetColCount();
693 nsCellMap
* cellMap
= mFirstMap
;
694 PRInt32 rowCount
= 0;
696 if (cellMap
== aCellMap
) {
697 cellMap
->RebuildConsideringRows(*this, aStartRowIndex
, aRowsToInsert
, aNumRowsToRemove
, aDamageArea
);
700 cellMap
->RebuildConsideringCells(*this, numOrigCols
, nsnull
, -1, 0, PR_FALSE
, aDamageArea
);
702 rowCount
+= cellMap
->GetRowCount();
703 cellMap
= cellMap
->GetNextSibling();
705 SetDamageArea(0, 0, GetColCount(), rowCount
, aDamageArea
);
709 nsTableCellMap::GetNumCellsOriginatingInCol(PRInt32 aColIndex
) const
711 PRInt32 colCount
= mCols
.Length();
712 if ((aColIndex
>= 0) && (aColIndex
< colCount
)) {
713 return mCols
.ElementAt(aColIndex
).mNumCellsOrig
;
716 NS_ERROR("nsCellMap::GetNumCellsOriginatingInCol - bad col index");
723 nsTableCellMap::Dump(char* aString
) const
726 printf("%s \n", aString
);
727 printf("***** START TABLE CELL MAP DUMP ***** %p\n", (void*)this);
729 PRInt32 colCount
= mCols
.Length();
730 printf ("cols array orig/span-> %p", (void*)this);
731 for (PRInt32 colX
= 0; colX
< colCount
; colX
++) {
732 const nsColInfo
& colInfo
= mCols
.ElementAt(colX
);
733 printf ("%d=%d/%d ", colX
, colInfo
.mNumCellsOrig
, colInfo
.mNumCellsSpan
);
735 printf(" cols in cache %d\n", mTableFrame
.GetColCache().Length());
736 nsCellMap
* cellMap
= mFirstMap
;
738 cellMap
->Dump(nsnull
!= mBCInfo
);
739 cellMap
= cellMap
->GetNextSibling();
741 if (nsnull
!= mBCInfo
) {
742 printf("***** bottom borders *****\n");
749 PRInt32 numCols
= mBCInfo
->mBottomBorders
.Length();
750 for (PRInt32 i
= 0; i
<= 2; i
++) {
753 for (colIndex
= 0; colIndex
< numCols
; colIndex
++) {
754 BCData
& cd
= mBCInfo
->mBottomBorders
.ElementAt(colIndex
);
756 size
= cd
.GetTopEdge(owner
, segStart
);
757 printf("t=%d%X%d ", size
, owner
, segStart
);
760 size
= cd
.GetLeftEdge(owner
, segStart
);
761 printf("l=%d%X%d ", size
, owner
, segStart
);
764 size
= cd
.GetCorner(side
, bevel
);
765 printf("c=%d%X%d ", size
, side
, bevel
);
768 BCData
& cd
= mBCInfo
->mLowerRightCorner
;
770 size
= cd
.GetTopEdge(owner
, segStart
);
771 printf("t=%d%X%d ", size
, owner
, segStart
);
774 size
= cd
.GetLeftEdge(owner
, segStart
);
775 printf("l=%d%X%d ", size
, owner
, segStart
);
778 size
= cd
.GetCorner(side
, bevel
);
779 printf("c=%d%X%d ", size
, side
, bevel
);
784 printf("***** END TABLE CELL MAP DUMP *****\n");
789 nsTableCellMap::GetCellInfoAt(PRInt32 aRowIndex
,
792 PRInt32
* aColSpan
) const
794 PRInt32 rowIndex
= aRowIndex
;
795 nsCellMap
* cellMap
= mFirstMap
;
797 if (cellMap
->GetRowCount() > rowIndex
) {
798 return cellMap
->GetCellInfoAt(*this, rowIndex
, aColIndex
, aOriginates
, aColSpan
);
800 rowIndex
-= cellMap
->GetRowCount();
801 cellMap
= cellMap
->GetNextSibling();
807 nsTableCellMap::GetIndexByRowAndColumn(PRInt32 aRow
, PRInt32 aColumn
) const
811 PRInt32 colCount
= mCols
.Length();
812 PRInt32 rowIndex
= aRow
;
814 nsCellMap
* cellMap
= mFirstMap
;
816 PRInt32 rowCount
= cellMap
->GetRowCount();
817 if (rowIndex
>= rowCount
) {
818 // If the rowCount is less than the rowIndex, this means that the index is
819 // not within the current map. If so, get the index of the last cell in
821 rowIndex
-= rowCount
;
823 PRInt32 cellMapIdx
= cellMap
->GetHighestIndex(colCount
);
824 if (cellMapIdx
!= -1)
825 index
+= cellMapIdx
+ 1;
828 // Index is in valid range for this cellmap, so get the index of rowIndex
830 PRInt32 cellMapIdx
= cellMap
->GetIndexByRowAndColumn(colCount
, rowIndex
,
832 if (cellMapIdx
== -1)
833 return -1; // no cell at the given row and column.
836 return index
; // no need to look through further maps here
839 cellMap
= cellMap
->GetNextSibling();
846 nsTableCellMap::GetRowAndColumnByIndex(PRInt32 aIndex
,
847 PRInt32
*aRow
, PRInt32
*aColumn
) const
852 PRInt32 colCount
= mCols
.Length();
854 PRInt32 previousRows
= 0;
855 PRInt32 index
= aIndex
;
857 nsCellMap
* cellMap
= mFirstMap
;
859 PRInt32 rowCount
= cellMap
->GetRowCount();
860 // Determine the highest possible index in this map to see
861 // if wanted index is in here.
862 PRInt32 cellMapIdx
= cellMap
->GetHighestIndex(colCount
);
863 if (cellMapIdx
== -1) {
864 // The index is not within this map, increase the total row index
866 previousRows
+= rowCount
;
868 if (index
> cellMapIdx
) {
869 // The index is not within this map, so decrease it by the cellMapIdx
870 // determined index and increase the total row index accordingly.
871 index
-= cellMapIdx
+ 1;
872 previousRows
+= rowCount
;
874 cellMap
->GetRowAndColumnByIndex(colCount
, index
, aRow
, aColumn
);
875 // If there were previous indexes, take them into account.
876 *aRow
+= previousRows
;
877 return; // no need to look any further.
881 cellMap
= cellMap
->GetNextSibling();
885 PRBool
nsTableCellMap::RowIsSpannedInto(PRInt32 aRowIndex
,
886 PRInt32 aNumEffCols
) const
888 PRInt32 rowIndex
= aRowIndex
;
889 nsCellMap
* cellMap
= mFirstMap
;
891 if (cellMap
->GetRowCount() > rowIndex
) {
892 return cellMap
->RowIsSpannedInto(rowIndex
, aNumEffCols
);
894 rowIndex
-= cellMap
->GetRowCount();
895 cellMap
= cellMap
->GetNextSibling();
900 PRBool
nsTableCellMap::RowHasSpanningCells(PRInt32 aRowIndex
,
901 PRInt32 aNumEffCols
) const
903 PRInt32 rowIndex
= aRowIndex
;
904 nsCellMap
* cellMap
= mFirstMap
;
906 if (cellMap
->GetRowCount() > rowIndex
) {
907 return cellMap
->RowHasSpanningCells(rowIndex
, aNumEffCols
);
909 rowIndex
-= cellMap
->GetRowCount();
910 cellMap
= cellMap
->GetNextSibling();
915 PRBool
nsTableCellMap::ColIsSpannedInto(PRInt32 aColIndex
) const
917 PRBool result
= PR_FALSE
;
919 PRInt32 colCount
= mCols
.Length();
920 if ((aColIndex
>= 0) && (aColIndex
< colCount
)) {
921 result
= mCols
.ElementAt(aColIndex
).mNumCellsSpan
!= 0;
926 PRBool
nsTableCellMap::ColHasSpanningCells(PRInt32 aColIndex
) const
928 NS_PRECONDITION (aColIndex
< GetColCount(), "bad col index arg");
929 nsCellMap
* cellMap
= mFirstMap
;
931 if (cellMap
->ColHasSpanningCells(aColIndex
)) {
934 cellMap
= cellMap
->GetNextSibling();
939 void nsTableCellMap::ExpandZeroColSpans()
941 mTableFrame
.SetNeedColSpanExpansion(PR_FALSE
); // mark the work done
942 mTableFrame
.SetHasZeroColSpans(PR_FALSE
); // reset the bit, if there is a
943 // zerospan it will be set again.
944 nsCellMap
* cellMap
= mFirstMap
;
946 cellMap
->ExpandZeroColSpans(*this);
947 cellMap
= cellMap
->GetNextSibling();
952 nsTableCellMap::SetNotTopStart(PRUint8 aSide
,
956 PRBool aIsLowerRight
)
958 if (!mBCInfo
|| aIsLowerRight
) ABORT0();
960 BCCellData
* cellData
;
961 BCData
* bcData
= nsnull
;
967 cellData
= (BCCellData
*)aCellMap
.GetDataAt(aRowIndex
, aColIndex
);
969 bcData
= &cellData
->mData
;
972 NS_ASSERTION(aSide
== NS_SIDE_BOTTOM
, "program error");
973 // try the next row group
974 nsCellMap
* cellMap
= aCellMap
.GetNextSibling();
976 cellData
= (BCCellData
*)cellMap
->GetDataAt(0, aColIndex
);
978 bcData
= &cellData
->mData
;
981 bcData
= GetBottomMostBorder(aColIndex
);
989 cellData
= (BCCellData
*)aCellMap
.GetDataAt(aRowIndex
, aColIndex
);
991 bcData
= &cellData
->mData
;
994 NS_ASSERTION(aSide
== NS_SIDE_RIGHT
, "program error");
995 bcData
= GetRightMostBorder(aRowIndex
);
1000 bcData
->SetTopStart(PR_FALSE
);
1004 // store the aSide border segment at coord = (aRowIndex, aColIndex). For top/left, store
1005 // the info at coord. For bottom/left store it at the adjacent location so that it is
1006 // top/left at that location. If the new location is at the right or bottom edge of the
1007 // table, then store it one of the special arrays (right most borders, bottom most borders).
1009 nsTableCellMap::SetBCBorderEdge(PRUint8 aSide
,
1010 nsCellMap
& aCellMap
,
1011 PRUint32 aCellMapStart
,
1015 BCBorderOwner aOwner
,
1019 if (!mBCInfo
) ABORT0();
1021 BCCellData
* cellData
;
1022 PRInt32 lastIndex
, xIndex
, yIndex
;
1023 PRInt32 xPos
= aColIndex
;
1024 PRInt32 yPos
= aRowIndex
;
1025 PRInt32 rgYPos
= aRowIndex
- aCellMapStart
;
1029 case NS_SIDE_BOTTOM
:
1033 lastIndex
= xPos
+ aLength
- 1;
1034 for (xIndex
= xPos
; xIndex
<= lastIndex
; xIndex
++) {
1035 changed
= aChanged
&& (xIndex
== xPos
);
1036 BCData
* bcData
= nsnull
;
1037 cellData
= (BCCellData
*)aCellMap
.GetDataAt(rgYPos
, xIndex
);
1039 PRInt32 numRgRows
= aCellMap
.GetRowCount();
1040 if (yPos
< numRgRows
) { // add a dead cell data
1042 cellData
= (BCCellData
*)aCellMap
.AppendCell(*this, nsnull
, rgYPos
, PR_FALSE
, damageArea
); if (!cellData
) ABORT0();
1045 NS_ASSERTION(aSide
== NS_SIDE_BOTTOM
, "program error");
1046 // try the next non empty row group
1047 nsCellMap
* cellMap
= aCellMap
.GetNextSibling();
1048 while (cellMap
&& (0 == cellMap
->GetRowCount())) {
1049 cellMap
= cellMap
->GetNextSibling();
1052 cellData
= (BCCellData
*)cellMap
->GetDataAt(0, xIndex
);
1053 if (!cellData
) { // add a dead cell
1055 cellData
= (BCCellData
*)cellMap
->AppendCell(*this, nsnull
, 0, PR_FALSE
, damageArea
);
1058 else { // must be at the end of the table
1059 bcData
= GetBottomMostBorder(xIndex
);
1063 if (!bcData
&& cellData
) {
1064 bcData
= &cellData
->mData
;
1067 bcData
->SetTopEdge(aOwner
, aSize
, changed
);
1069 else NS_ERROR("Cellmap: Top edge not found");
1075 // since top, bottom borders were set, there should already be a cellData entry
1076 lastIndex
= rgYPos
+ aLength
- 1;
1077 for (yIndex
= rgYPos
; yIndex
<= lastIndex
; yIndex
++) {
1078 changed
= aChanged
&& (yIndex
== rgYPos
);
1079 cellData
= (BCCellData
*)aCellMap
.GetDataAt(yIndex
, xPos
);
1081 cellData
->mData
.SetLeftEdge(aOwner
, aSize
, changed
);
1084 NS_ASSERTION(aSide
== NS_SIDE_RIGHT
, "program error");
1085 BCData
* bcData
= GetRightMostBorder(yIndex
+ aCellMapStart
);
1087 bcData
->SetLeftEdge(aOwner
, aSize
, changed
);
1089 else NS_ERROR("Cellmap: Left edge not found");
1096 // store corner info (aOwner, aSubSize, aBevel). For aCorner = eTopLeft, store the info at
1097 // (aRowIndex, aColIndex). For eTopRight, store it in the entry to the right where
1098 // it would be top left. For eBottomRight, store it in the entry to the bottom. etc.
1100 nsTableCellMap::SetBCBorderCorner(Corner aCorner
,
1101 nsCellMap
& aCellMap
,
1102 PRUint32 aCellMapStart
,
1108 PRBool aIsBottomRight
)
1110 if (!mBCInfo
) ABORT0();
1112 if (aIsBottomRight
) {
1113 mBCInfo
->mLowerRightCorner
.SetCorner(aSubSize
, aOwner
, aBevel
);
1117 PRInt32 xPos
= aColIndex
;
1118 PRInt32 yPos
= aRowIndex
;
1119 PRInt32 rgYPos
= aRowIndex
- aCellMapStart
;
1121 if (eTopRight
== aCorner
) {
1124 else if (eBottomRight
== aCorner
) {
1129 else if (eBottomLeft
== aCorner
) {
1134 BCCellData
* cellData
= nsnull
;
1135 BCData
* bcData
= nsnull
;
1136 if (GetColCount() <= xPos
) {
1137 NS_ASSERTION(xPos
== GetColCount(), "program error");
1138 // at the right edge of the table as we checked the corner before
1139 NS_ASSERTION(!aIsBottomRight
, "should be handled before");
1140 bcData
= GetRightMostBorder(yPos
);
1143 cellData
= (BCCellData
*)aCellMap
.GetDataAt(rgYPos
, xPos
);
1145 PRInt32 numRgRows
= aCellMap
.GetRowCount();
1146 if (yPos
< numRgRows
) { // add a dead cell data
1148 cellData
= (BCCellData
*)aCellMap
.AppendCell(*this, nsnull
, rgYPos
, PR_FALSE
, damageArea
);
1151 // try the next non empty row group
1152 nsCellMap
* cellMap
= aCellMap
.GetNextSibling();
1153 while (cellMap
&& (0 == cellMap
->GetRowCount())) {
1154 cellMap
= cellMap
->GetNextSibling();
1157 cellData
= (BCCellData
*)cellMap
->GetDataAt(0, xPos
);
1158 if (!cellData
) { // add a dead cell
1160 cellData
= (BCCellData
*)cellMap
->AppendCell(*this, nsnull
, 0, PR_FALSE
, damageArea
);
1163 else { // must be a the bottom of the table
1164 bcData
= GetBottomMostBorder(xPos
);
1169 if (!bcData
&& cellData
) {
1170 bcData
= &cellData
->mData
;
1173 bcData
->SetCorner(aSubSize
, aOwner
, aBevel
);
1175 else NS_ERROR("program error: Corner not found");
1178 nsCellMap::nsCellMap(nsTableRowGroupFrame
& aRowGroup
, PRBool aIsBC
)
1179 : mRows(8), mContentRowCount(0), mRowGroupFrame(&aRowGroup
),
1180 mNextSibling(nsnull
), mIsBC(aIsBC
),
1181 mPresContext(aRowGroup
.PresContext())
1183 MOZ_COUNT_CTOR(nsCellMap
);
1184 NS_ASSERTION(mPresContext
, "Must have prescontext");
1187 nsCellMap::~nsCellMap()
1189 MOZ_COUNT_DTOR(nsCellMap
);
1191 PRUint32 mapRowCount
= mRows
.Length();
1192 for (PRUint32 rowX
= 0; rowX
< mapRowCount
; rowX
++) {
1193 CellDataArray
&row
= mRows
[rowX
];
1194 PRUint32 colCount
= row
.Length();
1195 for (PRUint32 colX
= 0; colX
< colCount
; colX
++) {
1196 DestroyCellData(row
[colX
]);
1205 NS_ASSERTION(!sEmptyRow
, "How did that happen?");
1206 sEmptyRow
= new nsCellMap::CellDataArray();
1207 NS_ENSURE_TRUE(sEmptyRow
, NS_ERROR_OUT_OF_MEMORY
);
1214 nsCellMap::Shutdown()
1221 nsCellMap::GetCellFrame(PRInt32 aRowIndexIn
,
1222 PRInt32 aColIndexIn
,
1224 PRBool aUseRowIfOverlap
) const
1226 PRInt32 rowIndex
= aRowIndexIn
- aData
.GetRowSpanOffset();
1227 PRInt32 colIndex
= aColIndexIn
- aData
.GetColSpanOffset();
1228 if (aData
.IsOverlap()) {
1229 if (aUseRowIfOverlap
) {
1230 colIndex
= aColIndexIn
;
1233 rowIndex
= aRowIndexIn
;
1238 mRows
.SafeElementAt(rowIndex
, *sEmptyRow
).SafeElementAt(colIndex
);
1240 return data
->GetCellFrame();
1246 nsCellMap::GetHighestIndex(PRInt32 aColCount
)
1249 PRInt32 rowCount
= mRows
.Length();
1250 for (PRInt32 rowIdx
= 0; rowIdx
< rowCount
; rowIdx
++) {
1251 const CellDataArray
& row
= mRows
[rowIdx
];
1253 for (PRInt32 colIdx
= 0; colIdx
< aColCount
; colIdx
++) {
1254 CellData
* data
= row
.SafeElementAt(colIdx
);
1255 // No data means row doesn't have more cells.
1268 nsCellMap::GetIndexByRowAndColumn(PRInt32 aColCount
,
1269 PRInt32 aRow
, PRInt32 aColumn
) const
1271 if (PRUint32(aRow
) >= mRows
.Length())
1275 PRInt32 lastColsIdx
= aColCount
- 1;
1277 // Find row index of the cell where row span is started.
1278 const CellDataArray
& row
= mRows
[aRow
];
1279 CellData
* data
= row
.SafeElementAt(aColumn
);
1280 PRInt32 origRow
= data
? aRow
- data
->GetRowSpanOffset() : aRow
;
1282 // Calculate cell index.
1283 for (PRInt32 rowIdx
= 0; rowIdx
<= origRow
; rowIdx
++) {
1284 const CellDataArray
& row
= mRows
[rowIdx
];
1285 PRInt32 colCount
= (rowIdx
== origRow
) ? aColumn
: lastColsIdx
;
1287 for (PRInt32 colIdx
= 0; colIdx
<= colCount
; colIdx
++) {
1288 data
= row
.SafeElementAt(colIdx
);
1289 // No data means row doesn't have more cells.
1298 // Given row and column don't point to the cell.
1306 nsCellMap::GetRowAndColumnByIndex(PRInt32 aColCount
, PRInt32 aIndex
,
1307 PRInt32
*aRow
, PRInt32
*aColumn
) const
1312 PRInt32 index
= aIndex
;
1313 PRInt32 rowCount
= mRows
.Length();
1315 for (PRInt32 rowIdx
= 0; rowIdx
< rowCount
; rowIdx
++) {
1316 const CellDataArray
& row
= mRows
[rowIdx
];
1318 for (PRInt32 colIdx
= 0; colIdx
< aColCount
; colIdx
++) {
1319 CellData
* data
= row
.SafeElementAt(colIdx
);
1321 // The row doesn't have more cells.
1337 PRBool
nsCellMap::Grow(nsTableCellMap
& aMap
,
1341 NS_ASSERTION(aNumRows
>= 1, "Why are we calling this?");
1343 // Get the number of cols we want to use for preallocating the row arrays.
1344 PRInt32 numCols
= aMap
.GetColCount();
1348 PRUint32 startRowIndex
= (aRowIndex
>= 0) ? aRowIndex
: mRows
.Length();
1349 NS_ASSERTION(startRowIndex
<= mRows
.Length(), "Missing grow call inbetween");
1351 return mRows
.InsertElementsAt(startRowIndex
, aNumRows
, numCols
) != nsnull
;
1354 void nsCellMap::GrowRow(CellDataArray
& aRow
,
1358 // Have to have the cast to get the template to do the right thing.
1359 aRow
.InsertElementsAt(aRow
.Length(), aNumCols
, (CellData
*)nsnull
);
1363 nsCellMap::InsertRows(nsTableCellMap
& aMap
,
1364 nsTArray
<nsTableRowFrame
*>& aRows
,
1365 PRInt32 aFirstRowIndex
,
1366 PRBool aConsiderSpans
,
1367 nsRect
& aDamageArea
)
1369 PRInt32 numCols
= aMap
.GetColCount();
1370 NS_ASSERTION(aFirstRowIndex
>= 0, "nsCellMap::InsertRows called with negative rowIndex");
1371 if (PRUint32(aFirstRowIndex
) > mRows
.Length()) {
1372 // create (aFirstRowIndex - mRows.Length()) empty rows up to aFirstRowIndex
1373 PRInt32 numEmptyRows
= aFirstRowIndex
- mRows
.Length();
1374 if (!Grow(aMap
, numEmptyRows
)) {
1379 if (!aConsiderSpans
) {
1380 // update mContentRowCount, since non-empty rows will be added
1381 mContentRowCount
= NS_MAX(aFirstRowIndex
, mContentRowCount
);
1382 ExpandWithRows(aMap
, aRows
, aFirstRowIndex
, aDamageArea
);
1386 // if any cells span into or out of the row being inserted, then rebuild
1387 PRBool spansCauseRebuild
= CellsSpanInOrOut(aFirstRowIndex
,
1388 aFirstRowIndex
, 0, numCols
- 1);
1390 // update mContentRowCount, since non-empty rows will be added
1391 mContentRowCount
= NS_MAX(aFirstRowIndex
, mContentRowCount
);
1393 // if any of the new cells span out of the new rows being added, then rebuild
1394 // XXX it would be better to only rebuild the portion of the map that follows the new rows
1395 if (!spansCauseRebuild
&& (PRUint32(aFirstRowIndex
) < mRows
.Length())) {
1396 spansCauseRebuild
= CellsSpanOut(aRows
);
1399 if (spansCauseRebuild
) {
1400 aMap
.RebuildConsideringRows(this, aFirstRowIndex
, &aRows
, 0, aDamageArea
);
1403 ExpandWithRows(aMap
, aRows
, aFirstRowIndex
, aDamageArea
);
1408 nsCellMap::RemoveRows(nsTableCellMap
& aMap
,
1409 PRInt32 aFirstRowIndex
,
1410 PRInt32 aNumRowsToRemove
,
1411 PRBool aConsiderSpans
,
1412 nsRect
& aDamageArea
)
1414 PRInt32 numRows
= mRows
.Length();
1415 PRInt32 numCols
= aMap
.GetColCount();
1417 if (aFirstRowIndex
>= numRows
) {
1418 // reduce the content based row count based on the function arguments
1419 // as they are known to be real rows even if the cell map did not create
1420 // rows for them before.
1421 mContentRowCount
-= aNumRowsToRemove
;
1424 if (!aConsiderSpans
) {
1425 ShrinkWithoutRows(aMap
, aFirstRowIndex
, aNumRowsToRemove
, aDamageArea
);
1428 PRInt32 endRowIndex
= aFirstRowIndex
+ aNumRowsToRemove
- 1;
1429 if (endRowIndex
>= numRows
) {
1430 NS_ERROR("nsCellMap::RemoveRows tried to remove too many rows");
1431 endRowIndex
= numRows
- 1;
1433 PRBool spansCauseRebuild
= CellsSpanInOrOut(aFirstRowIndex
, endRowIndex
,
1436 if (spansCauseRebuild
) {
1437 aMap
.RebuildConsideringRows(this, aFirstRowIndex
, nsnull
, aNumRowsToRemove
, aDamageArea
);
1440 ShrinkWithoutRows(aMap
, aFirstRowIndex
, aNumRowsToRemove
, aDamageArea
);
1448 nsCellMap::AppendCell(nsTableCellMap
& aMap
,
1449 nsTableCellFrame
* aCellFrame
,
1451 PRBool aRebuildIfNecessary
,
1452 nsRect
& aDamageArea
,
1453 PRInt32
* aColToBeginSearch
)
1455 NS_ASSERTION(!!aMap
.mBCInfo
== mIsBC
, "BC state mismatch");
1456 PRInt32 origNumMapRows
= mRows
.Length();
1457 PRInt32 origNumCols
= aMap
.GetColCount();
1458 PRBool zeroRowSpan
= PR_FALSE
;
1459 PRInt32 rowSpan
= (aCellFrame
) ? GetRowSpanForNewCell(aCellFrame
, aRowIndex
,
1461 // add new rows if necessary
1462 PRInt32 endRowIndex
= aRowIndex
+ rowSpan
- 1;
1463 if (endRowIndex
>= origNumMapRows
) {
1464 // XXXbz handle allocation failures?
1465 Grow(aMap
, 1 + endRowIndex
- origNumMapRows
);
1468 // get the first null or dead CellData in the desired row. It will equal origNumCols if there are none
1469 CellData
* origData
= nsnull
;
1470 PRInt32 startColIndex
= 0;
1471 if (aColToBeginSearch
)
1472 startColIndex
= *aColToBeginSearch
;
1473 for (; startColIndex
< origNumCols
; startColIndex
++) {
1474 CellData
* data
= GetDataAt(aRowIndex
, startColIndex
);
1477 if (data
->IsDead()) {
1481 if (data
->IsZeroColSpan() ) {
1482 // appending a cell collapses zerospans.
1483 CollapseZeroColSpan(aMap
, data
, aRowIndex
, startColIndex
);
1484 // ask again for the data as it should be modified
1485 origData
= GetDataAt(aRowIndex
, startColIndex
);
1486 NS_ASSERTION(origData
->IsDead(),
1487 "The cellposition should have been cleared");
1491 // We found the place to append the cell, when the next cell is appended
1492 // the next search does not need to duplicate the search but can start
1493 // just at the next cell.
1494 if (aColToBeginSearch
)
1495 *aColToBeginSearch
= startColIndex
+ 1;
1497 PRBool zeroColSpan
= PR_FALSE
;
1498 PRInt32 colSpan
= (aCellFrame
) ?
1499 GetColSpanForNewCell(*aCellFrame
, zeroColSpan
) : 1;
1501 aMap
.mTableFrame
.SetHasZeroColSpans(PR_TRUE
);
1502 aMap
.mTableFrame
.SetNeedColSpanExpansion(PR_TRUE
);
1505 // if the new cell could potentially span into other rows and collide with
1506 // originating cells there, we will play it safe and just rebuild the map
1507 if (aRebuildIfNecessary
&& (aRowIndex
< mContentRowCount
- 1) && (rowSpan
> 1)) {
1508 nsAutoTArray
<nsTableCellFrame
*, 1> newCellArray
;
1509 newCellArray
.AppendElement(aCellFrame
);
1510 aMap
.RebuildConsideringCells(this, &newCellArray
, aRowIndex
, startColIndex
, PR_TRUE
, aDamageArea
);
1513 mContentRowCount
= NS_MAX(mContentRowCount
, aRowIndex
+ 1);
1515 // add new cols to the table map if necessary
1516 PRInt32 endColIndex
= startColIndex
+ colSpan
- 1;
1517 if (endColIndex
>= origNumCols
) {
1518 NS_ASSERTION(aCellFrame
, "dead cells should not require new columns");
1519 aMap
.AddColsAtEnd(1 + endColIndex
- origNumCols
);
1522 // Setup CellData for this cell
1524 NS_ASSERTION(origData
->IsDead(), "replacing a non dead cell is a memory leak");
1525 if (aCellFrame
) { // do nothing to replace a dead cell with a dead cell
1526 origData
->Init(aCellFrame
);
1527 // we are replacing a dead cell, increase the number of cells
1528 // originating at this column
1529 nsColInfo
* colInfo
= aMap
.GetColInfoAt(startColIndex
);
1530 NS_ASSERTION(colInfo
, "access to a non existing column");
1532 colInfo
->mNumCellsOrig
++;
1537 origData
= AllocCellData(aCellFrame
);
1538 if (!origData
) ABORT1(origData
);
1539 SetDataAt(aMap
, *origData
, aRowIndex
, startColIndex
);
1542 SetDamageArea(startColIndex
, aRowIndex
, 1 + endColIndex
- startColIndex
, 1 + endRowIndex
- aRowIndex
, aDamageArea
);
1548 // initialize the cell frame
1549 aCellFrame
->SetColIndex(startColIndex
);
1551 // Create CellData objects for the rows that this cell spans. Set
1552 // their mOrigCell to nsnull and their mSpanData to point to data.
1553 for (PRInt32 rowX
= aRowIndex
; rowX
<= endRowIndex
; rowX
++) {
1554 // The row at rowX will need to have at least endColIndex columns
1555 mRows
[rowX
].SetCapacity(endColIndex
);
1556 for (PRInt32 colX
= startColIndex
; colX
<= endColIndex
; colX
++) {
1557 if ((rowX
!= aRowIndex
) || (colX
!= startColIndex
)) { // skip orig cell data done above
1558 CellData
* cellData
= GetDataAt(rowX
, colX
);
1560 if (cellData
->IsOrig()) {
1561 NS_ERROR("cannot overlap originating cell");
1564 if (rowX
> aRowIndex
) { // row spanning into cell
1565 if (cellData
->IsRowSpan()) {
1566 // do nothing, this can be caused by rowspan which is overlapped
1567 // by a another cell with a rowspan and a colspan
1570 cellData
->SetRowSpanOffset(rowX
- aRowIndex
);
1572 cellData
->SetZeroRowSpan(PR_TRUE
);
1576 if (colX
> startColIndex
) { // col spanning into cell
1577 if (!cellData
->IsColSpan()) {
1578 if (cellData
->IsRowSpan()) {
1579 cellData
->SetOverlap(PR_TRUE
);
1581 cellData
->SetColSpanOffset(colX
- startColIndex
);
1583 cellData
->SetZeroColSpan(PR_TRUE
);
1586 nsColInfo
* colInfo
= aMap
.GetColInfoAt(colX
);
1587 colInfo
->mNumCellsSpan
++;
1592 cellData
= AllocCellData(nsnull
);
1593 if (!cellData
) return origData
;
1594 if (rowX
> aRowIndex
) {
1595 cellData
->SetRowSpanOffset(rowX
- aRowIndex
);
1597 cellData
->SetZeroRowSpan(PR_TRUE
);
1600 if (colX
> startColIndex
) {
1601 cellData
->SetColSpanOffset(colX
- startColIndex
);
1603 cellData
->SetZeroColSpan(PR_TRUE
);
1606 SetDataAt(aMap
, *cellData
, rowX
, colX
);
1611 #ifdef DEBUG_TABLE_CELLMAP
1612 printf("appended cell=%p row=%d \n", aCellFrame
, aRowIndex
);
1618 void nsCellMap::CollapseZeroColSpan(nsTableCellMap
& aMap
,
1619 CellData
* aOrigData
,
1623 // if after a colspan = 0 cell another cell is appended in a row the html 4
1624 // spec is already violated. In principle one should then append the cell
1625 // after the last column but then the zero spanning cell would also have
1626 // to grow. The only plausible way to break this cycle is ignore the zero
1627 // colspan and reset the cell to colspan = 1.
1629 NS_ASSERTION(aOrigData
&& aOrigData
->IsZeroColSpan(),
1630 "zero colspan should have been passed");
1631 // find the originating cellframe
1632 nsTableCellFrame
* cell
= GetCellFrame(aRowIndex
, aColIndex
, *aOrigData
, PR_TRUE
);
1633 NS_ASSERTION(cell
, "originating cell not found");
1635 // find the clearing region
1636 PRInt32 startRowIndex
= aRowIndex
- aOrigData
->GetRowSpanOffset();
1638 PRInt32 rowSpan
= GetRowSpanForNewCell(cell
, startRowIndex
, zeroSpan
);
1639 PRInt32 endRowIndex
= startRowIndex
+ rowSpan
;
1641 PRInt32 origColIndex
= aColIndex
- aOrigData
->GetColSpanOffset();
1642 PRInt32 endColIndex
= origColIndex
+
1643 GetEffectiveColSpan(aMap
, startRowIndex
,
1644 origColIndex
, zeroSpan
);
1645 for (PRInt32 colX
= origColIndex
+1; colX
< endColIndex
; colX
++) {
1646 // Start the collapse just after the originating cell, since
1647 // we're basically making the originating cell act as if it
1649 nsColInfo
* colInfo
= aMap
.GetColInfoAt(colX
);
1650 colInfo
->mNumCellsSpan
-= rowSpan
;
1652 for (PRInt32 rowX
= startRowIndex
; rowX
< endRowIndex
; rowX
++)
1654 CellData
* data
= mRows
[rowX
][colX
];
1655 NS_ASSERTION(data
->IsZeroColSpan(),
1656 "Overwriting previous data - memory leak");
1657 data
->Init(nsnull
); // mark the cell as a dead cell.
1662 PRBool
nsCellMap::CellsSpanOut(nsTArray
<nsTableRowFrame
*>& aRows
) const
1664 PRInt32 numNewRows
= aRows
.Length();
1665 for (PRInt32 rowX
= 0; rowX
< numNewRows
; rowX
++) {
1666 nsIFrame
* rowFrame
= (nsIFrame
*) aRows
.ElementAt(rowX
);
1667 nsIFrame
* childFrame
= rowFrame
->GetFirstChild(nsnull
);
1668 while (childFrame
) {
1669 nsTableCellFrame
*cellFrame
= do_QueryFrame(childFrame
);
1672 PRInt32 rowSpan
= GetRowSpanForNewCell(cellFrame
, rowX
, zeroSpan
);
1673 if (rowX
+ rowSpan
> numNewRows
) {
1677 childFrame
= childFrame
->GetNextSibling();
1683 // return PR_TRUE if any cells have rows spans into or out of the region
1684 // defined by the row and col indices or any cells have colspans into the region
1685 PRBool
nsCellMap::CellsSpanInOrOut(PRInt32 aStartRowIndex
,
1686 PRInt32 aEndRowIndex
,
1687 PRInt32 aStartColIndex
,
1688 PRInt32 aEndColIndex
) const
1691 * this routine will watch the cells adjacent to the region or at the edge
1692 * they are marked with *. The routine will verify whether they span in or
1696 * r1c1 r1c2 r1c3 r1c4 r1c5 r1rc6 r1c7
1697 * startrow r2c1 r2c2 *r2c3 *r2c4 *r2c5 *r2rc6 r2c7
1698 * endrow r3c1 r3c2 *r3c3 r3c4 r3c5 *r3rc6 r3c7
1699 * r4c1 r4c2 *r4c3 *r4c4 *r4c5 r4rc6 r4c7
1700 * r5c1 r5c2 r5c3 r5c4 r5c5 r5rc6 r5c7
1703 PRInt32 numRows
= mRows
.Length(); // use the cellmap rows to determine the
1704 // current cellmap extent.
1705 for (PRInt32 colX
= aStartColIndex
; colX
<= aEndColIndex
; colX
++) {
1707 if (aStartRowIndex
> 0) {
1708 cellData
= GetDataAt(aStartRowIndex
, colX
);
1709 if (cellData
&& (cellData
->IsRowSpan())) {
1710 return PR_TRUE
; // there is a row span into the region
1712 if ((aStartRowIndex
>= mContentRowCount
) && (mContentRowCount
> 0)) {
1713 cellData
= GetDataAt(mContentRowCount
- 1, colX
);
1714 if (cellData
&& cellData
->IsZeroRowSpan()) {
1715 return PR_TRUE
; // When we expand the zerospan it'll span into our row
1719 if (aEndRowIndex
< numRows
- 1) { // is there anything below aEndRowIndex
1720 cellData
= GetDataAt(aEndRowIndex
+ 1, colX
);
1721 if ((cellData
) && (cellData
->IsRowSpan())) {
1722 return PR_TRUE
; // there is a row span out of the region
1726 cellData
= GetDataAt(aEndRowIndex
, colX
);
1727 if ((cellData
) && (cellData
->IsRowSpan()) && (mContentRowCount
< numRows
)) {
1728 return PR_TRUE
; // this cell might be the cause of a dead row
1732 if (aStartColIndex
> 0) {
1733 for (PRInt32 rowX
= aStartRowIndex
; rowX
<= aEndRowIndex
; rowX
++) {
1734 CellData
* cellData
= GetDataAt(rowX
, aStartColIndex
);
1735 if (cellData
&& (cellData
->IsColSpan())) {
1736 return PR_TRUE
; // there is a col span into the region
1738 cellData
= GetDataAt(rowX
, aEndColIndex
+ 1);
1739 if (cellData
&& (cellData
->IsColSpan())) {
1740 return PR_TRUE
; // there is a col span out of the region
1747 void nsCellMap::InsertCells(nsTableCellMap
& aMap
,
1748 nsTArray
<nsTableCellFrame
*>& aCellFrames
,
1750 PRInt32 aColIndexBefore
,
1751 nsRect
& aDamageArea
)
1753 if (aCellFrames
.Length() == 0) return;
1754 NS_ASSERTION(aColIndexBefore
>= -1, "index out of range");
1755 PRInt32 numCols
= aMap
.GetColCount();
1756 if (aColIndexBefore
>= numCols
) {
1757 NS_ERROR("Inserting instead of appending cells indicates a serious cellmap error");
1758 aColIndexBefore
= numCols
- 1;
1761 // get the starting col index of the 1st new cells
1762 PRInt32 startColIndex
;
1763 for (startColIndex
= aColIndexBefore
+ 1; startColIndex
< numCols
; startColIndex
++) {
1764 CellData
* data
= GetDataAt(aRowIndex
, startColIndex
);
1765 if (!data
|| data
->IsOrig() || data
->IsDead()) {
1766 // // Not a span. Stop.
1769 if (data
->IsZeroColSpan()) {
1770 // Zero colspans collapse. Stop in this case too.
1771 CollapseZeroColSpan(aMap
, data
, aRowIndex
, startColIndex
);
1776 // record whether inserted cells are going to cause complications due
1777 // to existing row spans, col spans or table sizing.
1778 PRBool spansCauseRebuild
= PR_FALSE
;
1780 // check that all cells have the same row span
1781 PRInt32 numNewCells
= aCellFrames
.Length();
1782 PRBool zeroRowSpan
= PR_FALSE
;
1783 PRInt32 rowSpan
= 0;
1784 for (PRInt32 cellX
= 0; cellX
< numNewCells
; cellX
++) {
1785 nsTableCellFrame
* cell
= aCellFrames
.ElementAt(cellX
);
1786 PRInt32 rowSpan2
= GetRowSpanForNewCell(cell
, aRowIndex
, zeroRowSpan
);
1790 else if (rowSpan
!= rowSpan2
) {
1791 spansCauseRebuild
= PR_TRUE
;
1796 // check if the new cells will cause the table to add more rows
1797 if (!spansCauseRebuild
) {
1798 if (mRows
.Length() < PRUint32(aRowIndex
+ rowSpan
)) {
1799 spansCauseRebuild
= PR_TRUE
;
1803 if (!spansCauseRebuild
) {
1804 spansCauseRebuild
= CellsSpanInOrOut(aRowIndex
, aRowIndex
+ rowSpan
- 1,
1805 startColIndex
, numCols
- 1);
1808 if (spansCauseRebuild
) {
1809 aMap
.RebuildConsideringCells(this, &aCellFrames
, aRowIndex
, startColIndex
, PR_TRUE
, aDamageArea
);
1812 ExpandWithCells(aMap
, aCellFrames
, aRowIndex
, startColIndex
, rowSpan
, zeroRowSpan
, aDamageArea
);
1817 nsCellMap::ExpandWithRows(nsTableCellMap
& aMap
,
1818 nsTArray
<nsTableRowFrame
*>& aRowFrames
,
1819 PRInt32 aStartRowIndexIn
,
1820 nsRect
& aDamageArea
)
1822 PRInt32 startRowIndex
= (aStartRowIndexIn
>= 0) ? aStartRowIndexIn
: 0;
1823 NS_ASSERTION(PRUint32(startRowIndex
) <= mRows
.Length(), "caller should have grown cellmap before");
1825 PRInt32 numNewRows
= aRowFrames
.Length();
1826 mContentRowCount
+= numNewRows
;
1828 PRInt32 endRowIndex
= startRowIndex
+ numNewRows
- 1;
1830 // shift the rows after startRowIndex down and insert empty rows that will
1831 // be filled via the AppendCell call below
1832 if (!Grow(aMap
, numNewRows
, startRowIndex
)) {
1837 PRInt32 newRowIndex
= 0;
1838 for (PRInt32 rowX
= startRowIndex
; rowX
<= endRowIndex
; rowX
++) {
1839 nsTableRowFrame
* rFrame
= aRowFrames
.ElementAt(newRowIndex
);
1841 nsIFrame
* cFrame
= rFrame
->GetFirstChild(nsnull
);
1842 PRInt32 colIndex
= 0;
1844 nsTableCellFrame
*cellFrame
= do_QueryFrame(cFrame
);
1846 AppendCell(aMap
, cellFrame
, rowX
, PR_FALSE
, aDamageArea
, &colIndex
);
1848 cFrame
= cFrame
->GetNextSibling();
1853 SetDamageArea(0, startRowIndex
, aMap
.GetColCount(), 1 + endRowIndex
- startRowIndex
, aDamageArea
);
1856 void nsCellMap::ExpandWithCells(nsTableCellMap
& aMap
,
1857 nsTArray
<nsTableCellFrame
*>& aCellFrames
,
1860 PRInt32 aRowSpan
, // same for all cells
1861 PRBool aRowSpanIsZero
,
1862 nsRect
& aDamageArea
)
1864 NS_ASSERTION(!!aMap
.mBCInfo
== mIsBC
, "BC state mismatch");
1865 PRInt32 endRowIndex
= aRowIndex
+ aRowSpan
- 1;
1866 PRInt32 startColIndex
= aColIndex
;
1867 PRInt32 endColIndex
= aColIndex
;
1868 PRInt32 numCells
= aCellFrames
.Length();
1869 PRInt32 totalColSpan
= 0;
1871 // add cellData entries for the space taken up by the new cells
1872 for (PRInt32 cellX
= 0; cellX
< numCells
; cellX
++) {
1873 nsTableCellFrame
* cellFrame
= aCellFrames
.ElementAt(cellX
);
1874 CellData
* origData
= AllocCellData(cellFrame
); // the originating cell
1875 if (!origData
) return;
1877 // set the starting and ending col index for the new cell
1878 PRBool zeroColSpan
= PR_FALSE
;
1879 PRInt32 colSpan
= GetColSpanForNewCell(*cellFrame
, zeroColSpan
);
1881 aMap
.mTableFrame
.SetHasZeroColSpans(PR_TRUE
);
1882 aMap
.mTableFrame
.SetNeedColSpanExpansion(PR_TRUE
);
1884 totalColSpan
+= colSpan
;
1886 endColIndex
= aColIndex
+ colSpan
- 1;
1889 startColIndex
= endColIndex
+ 1;
1890 endColIndex
= startColIndex
+ colSpan
- 1;
1893 // add the originating cell data and any cell data corresponding to row/col spans
1894 for (PRInt32 rowX
= aRowIndex
; rowX
<= endRowIndex
; rowX
++) {
1895 CellDataArray
& row
= mRows
[rowX
];
1896 // Pre-allocate all the cells we'll need in this array, setting
1898 // Have to have the cast to get the template to do the right thing.
1899 PRInt32 insertionIndex
= row
.Length();
1900 if (insertionIndex
> startColIndex
) {
1901 insertionIndex
= startColIndex
;
1903 if (!row
.InsertElementsAt(insertionIndex
, endColIndex
- insertionIndex
+ 1,
1904 (CellData
*)nsnull
) &&
1905 rowX
== aRowIndex
) {
1906 // Failed to insert the slots, and this is the very first row. That
1907 // means that we need to clean up |origData| before returning, since
1908 // the cellmap doesn't own it yet.
1909 DestroyCellData(origData
);
1913 for (PRInt32 colX
= startColIndex
; colX
<= endColIndex
; colX
++) {
1914 CellData
* data
= origData
;
1915 if ((rowX
!= aRowIndex
) || (colX
!= startColIndex
)) {
1916 data
= AllocCellData(nsnull
);
1918 if (rowX
> aRowIndex
) {
1919 data
->SetRowSpanOffset(rowX
- aRowIndex
);
1920 if (aRowSpanIsZero
) {
1921 data
->SetZeroRowSpan(PR_TRUE
);
1924 if (colX
> startColIndex
) {
1925 data
->SetColSpanOffset(colX
- startColIndex
);
1927 data
->SetZeroColSpan(PR_TRUE
);
1931 SetDataAt(aMap
, *data
, rowX
, colX
);
1934 cellFrame
->SetColIndex(startColIndex
);
1936 PRInt32 damageHeight
= NS_MIN(GetRowGroup()->GetRowCount() - aRowIndex
, aRowSpan
);
1937 SetDamageArea(aColIndex
, aRowIndex
, 1 + endColIndex
- aColIndex
, damageHeight
, aDamageArea
);
1941 // update the row and col info due to shifting
1942 for (rowX
= aRowIndex
; rowX
<= endRowIndex
; rowX
++) {
1943 CellDataArray
& row
= mRows
[rowX
];
1944 PRUint32 numCols
= row
.Length();
1946 for (colX
= aColIndex
+ totalColSpan
; colX
< numCols
; colX
++) {
1947 CellData
* data
= row
[colX
];
1949 // increase the origin and span counts beyond the spanned cols
1950 if (data
->IsOrig()) {
1951 // a cell that gets moved needs adjustment as well as it new orignating col
1952 data
->GetCellFrame()->SetColIndex(colX
);
1953 nsColInfo
* colInfo
= aMap
.GetColInfoAt(colX
);
1954 colInfo
->mNumCellsOrig
++;
1956 if (data
->IsColSpan()) {
1957 nsColInfo
* colInfo
= aMap
.GetColInfoAt(colX
);
1958 colInfo
->mNumCellsSpan
++;
1961 // decrease the origin and span counts within the spanned cols
1962 PRInt32 colX2
= colX
- totalColSpan
;
1963 nsColInfo
* colInfo2
= aMap
.GetColInfoAt(colX2
);
1964 if (data
->IsOrig()) {
1965 // the old originating col of a moved cell needs adjustment
1966 colInfo2
->mNumCellsOrig
--;
1968 if (data
->IsColSpan()) {
1969 colInfo2
->mNumCellsSpan
--;
1976 void nsCellMap::ShrinkWithoutRows(nsTableCellMap
& aMap
,
1977 PRInt32 aStartRowIndex
,
1978 PRInt32 aNumRowsToRemove
,
1979 nsRect
& aDamageArea
)
1981 NS_ASSERTION(!!aMap
.mBCInfo
== mIsBC
, "BC state mismatch");
1982 PRInt32 endRowIndex
= aStartRowIndex
+ aNumRowsToRemove
- 1;
1983 PRUint32 colCount
= aMap
.GetColCount();
1984 for (PRInt32 rowX
= endRowIndex
; rowX
>= aStartRowIndex
; --rowX
) {
1985 CellDataArray
& row
= mRows
[rowX
];
1987 for (colX
= 0; colX
< colCount
; colX
++) {
1988 CellData
* data
= row
.SafeElementAt(colX
);
1990 // Adjust the column counts.
1991 if (data
->IsOrig()) {
1992 // Decrement the column count.
1993 nsColInfo
* colInfo
= aMap
.GetColInfoAt(colX
);
1994 colInfo
->mNumCellsOrig
--;
1996 // colspan=0 is only counted as a spanned cell in the 1st col it spans
1997 else if (data
->IsColSpan()) {
1998 nsColInfo
* colInfo
= aMap
.GetColInfoAt(colX
);
1999 colInfo
->mNumCellsSpan
--;
2004 PRUint32 rowLength
= row
.Length();
2005 // Delete our row information.
2006 for (colX
= 0; colX
< rowLength
; colX
++) {
2007 DestroyCellData(row
[colX
]);
2010 mRows
.RemoveElementAt(rowX
);
2012 // Decrement our row and next available index counts.
2015 aMap
.RemoveColsAtEnd();
2017 SetDamageArea(0, aStartRowIndex
, aMap
.GetColCount(), 0, aDamageArea
);
2020 PRInt32
nsCellMap::GetColSpanForNewCell(nsTableCellFrame
& aCellFrameToAdd
,
2021 PRBool
& aIsZeroColSpan
) const
2023 aIsZeroColSpan
= PR_FALSE
;
2024 PRInt32 colSpan
= aCellFrameToAdd
.GetColSpan();
2026 colSpan
= 1; // set the min colspan it will be expanded later
2027 aIsZeroColSpan
= PR_TRUE
;
2032 PRInt32
nsCellMap::GetEffectiveColSpan(const nsTableCellMap
& aMap
,
2035 PRBool
& aZeroColSpan
) const
2037 PRInt32 numColsInTable
= aMap
.GetColCount();
2038 aZeroColSpan
= PR_FALSE
;
2039 PRInt32 colSpan
= 1;
2040 if (PRUint32(aRowIndex
) >= mRows
.Length()) {
2044 const CellDataArray
& row
= mRows
[aRowIndex
];
2047 PRInt32 maxCols
= numColsInTable
;
2048 PRBool hitOverlap
= PR_FALSE
; // XXX this is not ever being set to PR_TRUE
2049 for (colX
= aColIndex
+ 1; colX
< maxCols
; colX
++) {
2050 data
= row
.SafeElementAt(colX
);
2052 // for an overlapping situation get the colspan from the originating cell and
2053 // use that as the max number of cols to iterate. Since this is rare, only
2054 // pay the price of looking up the cell's colspan here.
2055 if (!hitOverlap
&& data
->IsOverlap()) {
2056 CellData
* origData
= row
.SafeElementAt(aColIndex
);
2057 if (origData
&& origData
->IsOrig()) {
2058 nsTableCellFrame
* cellFrame
= origData
->GetCellFrame();
2060 // possible change the number of colums to iterate
2061 maxCols
= NS_MIN(aColIndex
+ cellFrame
->GetColSpan(), maxCols
);
2062 if (colX
>= maxCols
)
2067 if (data
->IsColSpan()) {
2069 if (data
->IsZeroColSpan()) {
2070 aZeroColSpan
= PR_TRUE
;
2083 nsCellMap::GetRowSpanForNewCell(nsTableCellFrame
* aCellFrameToAdd
,
2085 PRBool
& aIsZeroRowSpan
) const
2087 aIsZeroRowSpan
= PR_FALSE
;
2088 PRInt32 rowSpan
= aCellFrameToAdd
->GetRowSpan();
2090 // Use a min value of 2 for a zero rowspan to make computations easier
2091 // elsewhere. Zero rowspans are only content dependent!
2092 rowSpan
= NS_MAX(2, mContentRowCount
- aRowIndex
);
2093 aIsZeroRowSpan
= PR_TRUE
;
2098 PRBool
nsCellMap::HasMoreThanOneCell(PRInt32 aRowIndex
) const
2100 const CellDataArray
& row
= mRows
.SafeElementAt(aRowIndex
, *sEmptyRow
);
2101 PRUint32 maxColIndex
= row
.Length();
2104 for (colIndex
= 0; colIndex
< maxColIndex
; colIndex
++) {
2105 CellData
* cellData
= row
[colIndex
];
2106 if (cellData
&& (cellData
->GetCellFrame() || cellData
->IsRowSpan()))
2115 nsCellMap::GetNumCellsOriginatingInRow(PRInt32 aRowIndex
) const
2117 const CellDataArray
& row
= mRows
.SafeElementAt(aRowIndex
, *sEmptyRow
);
2119 PRUint32 maxColIndex
= row
.Length();
2121 for (colIndex
= 0; colIndex
< maxColIndex
; colIndex
++) {
2122 CellData
* cellData
= row
[colIndex
];
2123 if (cellData
&& cellData
->IsOrig())
2129 PRInt32
nsCellMap::GetRowSpan(PRInt32 aRowIndex
,
2131 PRBool aGetEffective
) const
2133 PRInt32 rowSpan
= 1;
2134 PRInt32 rowCount
= (aGetEffective
) ? mContentRowCount
: mRows
.Length();
2136 for (rowX
= aRowIndex
+ 1; rowX
< rowCount
; rowX
++) {
2137 CellData
* data
= GetDataAt(rowX
, aColIndex
);
2139 if (data
->IsRowSpan()) {
2151 void nsCellMap::ShrinkWithoutCell(nsTableCellMap
& aMap
,
2152 nsTableCellFrame
& aCellFrame
,
2155 nsRect
& aDamageArea
)
2157 NS_ASSERTION(!!aMap
.mBCInfo
== mIsBC
, "BC state mismatch");
2158 PRUint32 colX
, rowX
;
2160 // get the rowspan and colspan from the cell map since the content may have changed
2162 PRUint32 numCols
= aMap
.GetColCount();
2163 PRInt32 rowSpan
= GetRowSpan(aRowIndex
, aColIndex
, PR_FALSE
);
2164 PRUint32 colSpan
= GetEffectiveColSpan(aMap
, aRowIndex
, aColIndex
, zeroColSpan
);
2165 PRUint32 endRowIndex
= aRowIndex
+ rowSpan
- 1;
2166 PRUint32 endColIndex
= aColIndex
+ colSpan
- 1;
2168 SetDamageArea(aColIndex
, aRowIndex
, 1 + endColIndex
- aColIndex
, 1 + endRowIndex
- aRowIndex
, aDamageArea
);
2170 if (aMap
.mTableFrame
.HasZeroColSpans()) {
2171 aMap
.mTableFrame
.SetNeedColSpanExpansion(PR_TRUE
);
2174 // adjust the col counts due to the deleted cell before removing it
2175 for (colX
= aColIndex
; colX
<= endColIndex
; colX
++) {
2176 nsColInfo
* colInfo
= aMap
.GetColInfoAt(colX
);
2177 if (colX
== PRUint32(aColIndex
)) {
2178 colInfo
->mNumCellsOrig
--;
2181 colInfo
->mNumCellsSpan
--;
2185 // remove the deleted cell and cellData entries for it
2186 for (rowX
= aRowIndex
; rowX
<= endRowIndex
; rowX
++) {
2187 CellDataArray
& row
= mRows
[rowX
];
2189 // endIndexForRow points at the first slot we don't want to clean up. This
2190 // makes the aColIndex == 0 case work right with our unsigned int colX.
2191 NS_ASSERTION(endColIndex
+ 1 <= row
.Length(), "span beyond the row size!");
2192 PRUint32 endIndexForRow
= NS_MIN(endColIndex
+ 1, row
.Length());
2194 // Since endIndexForRow <= row.Length(), enough to compare aColIndex to it.
2195 if (PRUint32(aColIndex
) < endIndexForRow
) {
2196 for (colX
= endIndexForRow
; colX
> PRUint32(aColIndex
); colX
--) {
2197 DestroyCellData(row
[colX
-1]);
2199 row
.RemoveElementsAt(aColIndex
, endIndexForRow
- aColIndex
);
2203 numCols
= aMap
.GetColCount();
2205 // update the row and col info due to shifting
2206 for (rowX
= aRowIndex
; rowX
<= endRowIndex
; rowX
++) {
2207 CellDataArray
& row
= mRows
[rowX
];
2208 for (colX
= aColIndex
; colX
< numCols
- colSpan
; colX
++) {
2209 CellData
* data
= row
.SafeElementAt(colX
);
2211 if (data
->IsOrig()) {
2212 // a cell that gets moved to the left needs adjustment in its new location
2213 data
->GetCellFrame()->SetColIndex(colX
);
2214 nsColInfo
* colInfo
= aMap
.GetColInfoAt(colX
);
2215 colInfo
->mNumCellsOrig
++;
2216 // a cell that gets moved to the left needs adjustment in its old location
2217 colInfo
= aMap
.GetColInfoAt(colX
+ colSpan
);
2219 colInfo
->mNumCellsOrig
--;
2223 else if (data
->IsColSpan()) {
2224 // a cell that gets moved to the left needs adjustment
2225 // in its new location
2226 nsColInfo
* colInfo
= aMap
.GetColInfoAt(colX
);
2227 colInfo
->mNumCellsSpan
++;
2228 // a cell that gets moved to the left needs adjustment
2229 // in its old location
2230 colInfo
= aMap
.GetColInfoAt(colX
+ colSpan
);
2232 colInfo
->mNumCellsSpan
--;
2238 aMap
.RemoveColsAtEnd();
2242 nsCellMap::RebuildConsideringRows(nsTableCellMap
& aMap
,
2243 PRInt32 aStartRowIndex
,
2244 nsTArray
<nsTableRowFrame
*>* aRowsToInsert
,
2245 PRInt32 aNumRowsToRemove
,
2246 nsRect
& aDamageArea
)
2248 NS_ASSERTION(!!aMap
.mBCInfo
== mIsBC
, "BC state mismatch");
2249 // copy the old cell map into a new array
2250 PRUint32 numOrigRows
= mRows
.Length();
2251 nsTArray
<CellDataArray
> origRows
;
2252 mRows
.SwapElements(origRows
);
2254 PRInt32 rowNumberChange
;
2255 if (aRowsToInsert
) {
2256 rowNumberChange
= aRowsToInsert
->Length();
2258 rowNumberChange
= -aNumRowsToRemove
;
2261 // adjust mContentRowCount based on the function arguments as they are known to
2263 mContentRowCount
+= rowNumberChange
;
2264 NS_ASSERTION(mContentRowCount
>= 0, "previous mContentRowCount was wrong");
2265 // mRows is empty now. Grow it to the size we expect it to have.
2266 if (mContentRowCount
) {
2267 if (!Grow(aMap
, mContentRowCount
)) {
2268 // Bail, I guess... Not sure what else we can do here.
2273 // aStartRowIndex might be after all existing rows so we should limit the
2274 // copy to the amount of exisiting rows
2275 PRUint32 copyEndRowIndex
= NS_MIN(numOrigRows
, PRUint32(aStartRowIndex
));
2277 // rowX keeps track of where we are in mRows while setting up the
2281 // put back the rows before the affected ones just as before. Note that we
2282 // can't just copy the old rows in bit-for-bit, because they might be
2283 // spanning out into the rows we're adding/removing.
2284 for ( ; rowX
< copyEndRowIndex
; rowX
++) {
2285 const CellDataArray
& row
= origRows
[rowX
];
2286 PRUint32 numCols
= row
.Length();
2287 for (PRUint32 colX
= 0; colX
< numCols
; colX
++) {
2288 // put in the original cell from the cell map
2289 const CellData
* data
= row
.ElementAt(colX
);
2290 if (data
&& data
->IsOrig()) {
2291 AppendCell(aMap
, data
->GetCellFrame(), rowX
, PR_FALSE
, aDamageArea
);
2296 // Now handle the new rows being inserted, if any.
2297 PRUint32 copyStartRowIndex
;
2298 rowX
= aStartRowIndex
;
2299 if (aRowsToInsert
) {
2300 // add in the new cells and create rows if necessary
2301 PRInt32 numNewRows
= aRowsToInsert
->Length();
2302 for (PRInt32 newRowX
= 0; newRowX
< numNewRows
; newRowX
++) {
2303 nsTableRowFrame
* rFrame
= aRowsToInsert
->ElementAt(newRowX
);
2304 nsIFrame
* cFrame
= rFrame
->GetFirstChild(nsnull
);
2306 nsTableCellFrame
*cellFrame
= do_QueryFrame(cFrame
);
2308 AppendCell(aMap
, cellFrame
, rowX
, PR_FALSE
, aDamageArea
);
2310 cFrame
= cFrame
->GetNextSibling();
2314 copyStartRowIndex
= aStartRowIndex
;
2317 copyStartRowIndex
= aStartRowIndex
+ aNumRowsToRemove
;
2320 // put back the rows after the affected ones just as before. Again, we can't
2321 // just copy the old bits because that would not handle the new rows spanning
2322 // out or our earlier old rows spanning through the damaged area.
2323 for (PRUint32 copyRowX
= copyStartRowIndex
; copyRowX
< numOrigRows
;
2325 const CellDataArray
& row
= origRows
[copyRowX
];
2326 PRUint32 numCols
= row
.Length();
2327 for (PRUint32 colX
= 0; colX
< numCols
; colX
++) {
2328 // put in the original cell from the cell map
2329 CellData
* data
= row
.ElementAt(colX
);
2330 if (data
&& data
->IsOrig()) {
2331 AppendCell(aMap
, data
->GetCellFrame(), rowX
, PR_FALSE
, aDamageArea
);
2337 // delete the old cell map. Now rowX no longer has anything to do with mRows
2338 for (rowX
= 0; rowX
< numOrigRows
; rowX
++) {
2339 CellDataArray
& row
= origRows
[rowX
];
2340 PRUint32 len
= row
.Length();
2341 for (PRUint32 colX
= 0; colX
< len
; colX
++) {
2342 DestroyCellData(row
[colX
]);
2346 SetDamageArea(0, 0, aMap
.GetColCount(), GetRowCount(), aDamageArea
);
2350 nsCellMap::RebuildConsideringCells(nsTableCellMap
& aMap
,
2351 PRInt32 aNumOrigCols
,
2352 nsTArray
<nsTableCellFrame
*>* aCellFrames
,
2356 nsRect
& aDamageArea
)
2358 NS_ASSERTION(!!aMap
.mBCInfo
== mIsBC
, "BC state mismatch");
2359 // copy the old cell map into a new array
2360 PRInt32 numOrigRows
= mRows
.Length();
2361 nsTArray
<CellDataArray
> origRows
;
2362 mRows
.SwapElements(origRows
);
2364 PRInt32 numNewCells
= (aCellFrames
) ? aCellFrames
->Length() : 0;
2366 // the new cells might extend the previous column number
2367 NS_ASSERTION(aNumOrigCols
>= aColIndex
, "Appending cells far beyond cellmap data?!");
2368 PRInt32 numCols
= aInsert
? NS_MAX(aNumOrigCols
, aColIndex
+ 1) : aNumOrigCols
;
2370 // build the new cell map. Hard to say what, if anything, we can preallocate
2371 // here... Should come back to that sometime, perhaps.
2373 for (rowX
= 0; rowX
< numOrigRows
; rowX
++) {
2374 const CellDataArray
& row
= origRows
[rowX
];
2375 for (PRInt32 colX
= 0; colX
< numCols
; colX
++) {
2376 if ((rowX
== aRowIndex
) && (colX
== aColIndex
)) {
2377 if (aInsert
) { // put in the new cells
2378 for (PRInt32 cellX
= 0; cellX
< numNewCells
; cellX
++) {
2379 nsTableCellFrame
* cell
= aCellFrames
->ElementAt(cellX
);
2381 AppendCell(aMap
, cell
, rowX
, PR_FALSE
, aDamageArea
);
2386 continue; // do not put the deleted cell back
2389 // put in the original cell from the cell map
2390 CellData
* data
= row
.SafeElementAt(colX
);
2391 if (data
&& data
->IsOrig()) {
2392 AppendCell(aMap
, data
->GetCellFrame(), rowX
, PR_FALSE
, aDamageArea
);
2396 if (aInsert
&& numOrigRows
<= aRowIndex
) { // append the new cells below the last original row
2397 NS_ASSERTION (numOrigRows
== aRowIndex
, "Appending cells far beyond the last row");
2398 for (PRInt32 cellX
= 0; cellX
< numNewCells
; cellX
++) {
2399 nsTableCellFrame
* cell
= aCellFrames
->ElementAt(cellX
);
2401 AppendCell(aMap
, cell
, aRowIndex
, PR_FALSE
, aDamageArea
);
2406 // delete the old cell map
2407 for (rowX
= 0; rowX
< numOrigRows
; rowX
++) {
2408 CellDataArray
& row
= origRows
[rowX
];
2409 PRUint32 len
= row
.Length();
2410 for (PRUint32 colX
= 0; colX
< len
; colX
++) {
2411 DestroyCellData(row
.SafeElementAt(colX
));
2414 // expand the cellmap to cover empty content rows
2415 if (mRows
.Length() < PRUint32(mContentRowCount
)) {
2416 Grow(aMap
, mContentRowCount
- mRows
.Length());
2421 void nsCellMap::RemoveCell(nsTableCellMap
& aMap
,
2422 nsTableCellFrame
* aCellFrame
,
2424 nsRect
& aDamageArea
)
2426 PRUint32 numRows
= mRows
.Length();
2427 if (PRUint32(aRowIndex
) >= numRows
) {
2428 NS_ERROR("bad arg in nsCellMap::RemoveCell");
2431 PRInt32 numCols
= aMap
.GetColCount();
2433 // Now aRowIndex is guaranteed OK.
2435 // get the starting col index of the cell to remove
2436 PRInt32 startColIndex
;
2437 for (startColIndex
= 0; startColIndex
< numCols
; startColIndex
++) {
2438 CellData
* data
= mRows
[aRowIndex
].SafeElementAt(startColIndex
);
2439 if (data
&& (data
->IsOrig()) && (aCellFrame
== data
->GetCellFrame())) {
2440 break; // we found the col index
2444 PRInt32 rowSpan
= GetRowSpan(aRowIndex
, startColIndex
, PR_FALSE
);
2445 // record whether removing the cells is going to cause complications due
2446 // to existing row spans, col spans or table sizing.
2447 PRBool spansCauseRebuild
= CellsSpanInOrOut(aRowIndex
,
2448 aRowIndex
+ rowSpan
- 1,
2449 startColIndex
, numCols
- 1);
2450 // XXX if the cell has a col span to the end of the map, and the end has no originating
2451 // cells, we need to assume that this the only such cell, and rebuild so that there are
2452 // no extraneous cols at the end. The same is true for removing rows.
2453 if (!aCellFrame
->GetRowSpan() || !aCellFrame
->GetColSpan())
2454 spansCauseRebuild
= PR_TRUE
;
2456 if (spansCauseRebuild
) {
2457 aMap
.RebuildConsideringCells(this, nsnull
, aRowIndex
, startColIndex
, PR_FALSE
, aDamageArea
);
2460 ShrinkWithoutCell(aMap
, *aCellFrame
, aRowIndex
, startColIndex
, aDamageArea
);
2464 void nsCellMap::ExpandZeroColSpans(nsTableCellMap
& aMap
)
2466 NS_ASSERTION(!!aMap
.mBCInfo
== mIsBC
, "BC state mismatch");
2467 PRUint32 numRows
= mRows
.Length();
2468 PRUint32 numCols
= aMap
.GetColCount();
2469 PRUint32 rowIndex
, colIndex
;
2471 for (rowIndex
= 0; rowIndex
< numRows
; rowIndex
++) {
2472 for (colIndex
= 0; colIndex
< numCols
; colIndex
++) {
2473 CellData
* data
= mRows
[rowIndex
].SafeElementAt(colIndex
);
2474 if (!data
|| !data
->IsOrig())
2476 nsTableCellFrame
* cell
= data
->GetCellFrame();
2477 NS_ASSERTION(cell
, "There has to be a cell");
2478 PRInt32 cellRowSpan
= cell
->GetRowSpan();
2479 PRInt32 cellColSpan
= cell
->GetColSpan();
2480 PRBool rowZeroSpan
= (0 == cell
->GetRowSpan());
2481 PRBool colZeroSpan
= (0 == cell
->GetColSpan());
2483 aMap
.mTableFrame
.SetHasZeroColSpans(PR_TRUE
);
2485 NS_ASSERTION(numRows
> 0, "Bogus numRows");
2486 NS_ASSERTION(numCols
> 0, "Bogus numCols");
2487 PRUint32 endRowIndex
= rowZeroSpan
? numRows
- 1 :
2488 rowIndex
+ cellRowSpan
- 1;
2489 PRUint32 endColIndex
= colZeroSpan
? numCols
- 1 :
2490 colIndex
+ cellColSpan
- 1;
2491 PRUint32 colX
, rowX
;
2492 colX
= colIndex
+ 1;
2493 while (colX
<= endColIndex
) {
2494 // look at columns from here to our colspan. For each one, check
2495 // the rows from here to our rowspan to make sure there is no
2496 // obstacle to marking that column as a zerospanned column; if there
2497 // isn't, mark it so
2498 for (rowX
= rowIndex
; rowX
<= endRowIndex
; rowX
++) {
2499 CellData
* oldData
= GetDataAt(rowX
, colX
);
2501 if (oldData
->IsOrig()) {
2502 break; // something is in the way
2504 if (oldData
->IsRowSpan()) {
2505 if ((rowX
- rowIndex
) != oldData
->GetRowSpanOffset()) {
2509 if (oldData
->IsColSpan()) {
2510 if ((colX
- colIndex
) != oldData
->GetColSpanOffset()) {
2516 if (endRowIndex
>= rowX
)
2517 break;// we hit something
2518 for (rowX
= rowIndex
; rowX
<= endRowIndex
; rowX
++) {
2519 CellData
* newData
= AllocCellData(nsnull
);
2520 if (!newData
) return;
2522 newData
->SetColSpanOffset(colX
- colIndex
);
2523 newData
->SetZeroColSpan(PR_TRUE
);
2525 if (rowX
> rowIndex
) {
2526 newData
->SetRowSpanOffset(rowX
- rowIndex
);
2528 newData
->SetZeroRowSpan(PR_TRUE
);
2530 SetDataAt(aMap
, *newData
, rowX
, colX
);
2533 } // while (colX <= endColIndex)
2539 void nsCellMap::Dump(PRBool aIsBorderCollapse
) const
2541 printf("\n ***** START GROUP CELL MAP DUMP ***** %p\n", (void*)this);
2542 nsTableRowGroupFrame
* rg
= GetRowGroup();
2543 const nsStyleDisplay
* display
= rg
->GetStyleDisplay();
2544 switch (display
->mDisplay
) {
2545 case NS_STYLE_DISPLAY_TABLE_HEADER_GROUP
:
2548 case NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP
:
2551 case NS_STYLE_DISPLAY_TABLE_ROW_GROUP
:
2555 printf("HUH? wrong display type on rowgroup");
2557 PRUint32 mapRowCount
= mRows
.Length();
2558 printf("mapRowCount=%u tableRowCount=%d\n", mapRowCount
, mContentRowCount
);
2561 PRUint32 rowIndex
, colIndex
;
2562 for (rowIndex
= 0; rowIndex
< mapRowCount
; rowIndex
++) {
2563 const CellDataArray
& row
= mRows
[rowIndex
];
2564 printf(" row %d : ", rowIndex
);
2565 PRUint32 colCount
= row
.Length();
2566 for (colIndex
= 0; colIndex
< colCount
; colIndex
++) {
2567 CellData
* cd
= row
[colIndex
];
2570 printf("C%d,%d ", rowIndex
, colIndex
);
2572 nsTableCellFrame
* cell
= nsnull
;
2573 if (cd
->IsRowSpan()) {
2574 cell
= GetCellFrame(rowIndex
, colIndex
, *cd
, PR_TRUE
);
2577 if (cd
->IsColSpan()) {
2578 cell
= GetCellFrame(rowIndex
, colIndex
, *cd
, PR_FALSE
);
2581 if (!(cd
->IsRowSpan() && cd
->IsColSpan())) {
2590 if (aIsBorderCollapse
) {
2592 BCBorderOwner owner
;
2596 for (PRInt32 i
= 0; i
<= 2; i
++) {
2598 for (colIndex
= 0; colIndex
< colCount
; colIndex
++) {
2599 BCCellData
* cd
= (BCCellData
*)row
[colIndex
];
2602 size
= cd
->mData
.GetTopEdge(owner
, segStart
);
2603 printf("t=%d%d%d ", size
, owner
, segStart
);
2606 size
= cd
->mData
.GetLeftEdge(owner
, segStart
);
2607 printf("l=%d%d%d ", size
, owner
, segStart
);
2610 size
= cd
->mData
.GetCorner(side
, bevel
);
2611 printf("c=%d%d%d ", size
, side
, bevel
);
2620 // output info mapping Ci,j to cell address
2621 PRUint32 cellCount
= 0;
2622 for (PRUint32 rIndex
= 0; rIndex
< mapRowCount
; rIndex
++) {
2623 const CellDataArray
& row
= mRows
[rIndex
];
2624 PRUint32 colCount
= row
.Length();
2626 for (colIndex
= 0; colIndex
< colCount
; colIndex
++) {
2627 CellData
* cd
= row
[colIndex
];
2630 nsTableCellFrame
* cellFrame
= cd
->GetCellFrame();
2631 PRInt32 cellFrameColIndex
;
2632 cellFrame
->GetColIndex(cellFrameColIndex
);
2633 printf("C%d,%d=%p(%d) ", rIndex
, colIndex
, (void*)cellFrame
,
2642 printf(" ***** END GROUP CELL MAP DUMP *****\n");
2647 nsCellMap::IsZeroColSpan(PRInt32 aRowIndex
,
2648 PRInt32 aColIndex
) const
2651 mRows
.SafeElementAt(aRowIndex
, *sEmptyRow
).SafeElementAt(aColIndex
);
2652 return data
&& data
->IsZeroColSpan();
2656 nsCellMap::GetDataAt(PRInt32 aMapRowIndex
,
2657 PRInt32 aColIndex
) const
2660 mRows
.SafeElementAt(aMapRowIndex
, *sEmptyRow
).SafeElementAt(aColIndex
);
2663 // only called if the cell at aMapRowIndex, aColIndex is null or dead
2664 // (the latter from ExpandZeroColSpans).
2665 void nsCellMap::SetDataAt(nsTableCellMap
& aMap
,
2667 PRInt32 aMapRowIndex
,
2670 NS_ASSERTION(!!aMap
.mBCInfo
== mIsBC
, "BC state mismatch");
2671 if (PRUint32(aMapRowIndex
) >= mRows
.Length()) {
2672 NS_ERROR("SetDataAt called with row index > num rows");
2676 CellDataArray
& row
= mRows
[aMapRowIndex
];
2678 // the table map may need cols added
2679 PRInt32 numColsToAdd
= aColIndex
+ 1 - aMap
.GetColCount();
2680 if (numColsToAdd
> 0) {
2681 aMap
.AddColsAtEnd(numColsToAdd
);
2683 // the row may need cols added
2684 numColsToAdd
= aColIndex
+ 1 - row
.Length();
2685 if (numColsToAdd
> 0) {
2686 // XXXbz need to handle allocation failures.
2687 GrowRow(row
, numColsToAdd
);
2690 DestroyCellData(row
[aColIndex
]);
2692 row
.ReplaceElementsAt(aColIndex
, 1, &aNewCell
);
2693 // update the originating cell counts if cell originates in this row, col
2694 nsColInfo
* colInfo
= aMap
.GetColInfoAt(aColIndex
);
2696 if (aNewCell
.IsOrig()) {
2697 colInfo
->mNumCellsOrig
++;
2699 else if (aNewCell
.IsColSpan()) {
2700 colInfo
->mNumCellsSpan
++;
2703 else NS_ERROR("SetDataAt called with col index > table map num cols");
2707 nsCellMap::GetCellInfoAt(const nsTableCellMap
& aMap
,
2710 PRBool
* aOriginates
,
2711 PRInt32
* aColSpan
) const
2714 *aOriginates
= PR_FALSE
;
2716 CellData
* data
= GetDataAt(aRowX
, aColX
);
2717 nsTableCellFrame
* cellFrame
= nsnull
;
2719 if (data
->IsOrig()) {
2720 cellFrame
= data
->GetCellFrame();
2722 *aOriginates
= PR_TRUE
;
2725 cellFrame
= GetCellFrame(aRowX
, aColX
, *data
, PR_TRUE
);
2727 if (cellFrame
&& aColSpan
) {
2728 PRInt32 initialColIndex
;
2729 cellFrame
->GetColIndex(initialColIndex
);
2731 *aColSpan
= GetEffectiveColSpan(aMap
, aRowX
, initialColIndex
, zeroSpan
);
2738 PRBool
nsCellMap::RowIsSpannedInto(PRInt32 aRowIndex
,
2739 PRInt32 aNumEffCols
) const
2741 if ((0 > aRowIndex
) || (aRowIndex
>= mContentRowCount
)) {
2744 for (PRInt32 colIndex
= 0; colIndex
< aNumEffCols
; colIndex
++) {
2745 CellData
* cd
= GetDataAt(aRowIndex
, colIndex
);
2746 if (cd
) { // there's really a cell at (aRowIndex, colIndex)
2747 if (cd
->IsSpan()) { // the cell at (aRowIndex, colIndex) is the result of a span
2748 if (cd
->IsRowSpan() && GetCellFrame(aRowIndex
, colIndex
, *cd
, PR_TRUE
)) { // XXX why the last check
2757 PRBool
nsCellMap::RowHasSpanningCells(PRInt32 aRowIndex
,
2758 PRInt32 aNumEffCols
) const
2760 if ((0 > aRowIndex
) || (aRowIndex
>= mContentRowCount
)) {
2763 if (aRowIndex
!= mContentRowCount
- 1) {
2764 // aRowIndex is not the last row, so we check the next row after aRowIndex for spanners
2765 for (PRInt32 colIndex
= 0; colIndex
< aNumEffCols
; colIndex
++) {
2766 CellData
* cd
= GetDataAt(aRowIndex
, colIndex
);
2767 if (cd
&& (cd
->IsOrig())) { // cell originates
2768 CellData
* cd2
= GetDataAt(aRowIndex
+ 1, colIndex
);
2769 if (cd2
&& cd2
->IsRowSpan()) { // cd2 is spanned by a row
2770 if (cd
->GetCellFrame() == GetCellFrame(aRowIndex
+ 1, colIndex
, *cd2
, PR_TRUE
)) {
2780 PRBool
nsCellMap::ColHasSpanningCells(PRInt32 aColIndex
) const
2782 for (PRInt32 rowIndex
= 0; rowIndex
< mContentRowCount
; rowIndex
++) {
2783 CellData
* cd
= GetDataAt(rowIndex
, aColIndex
);
2784 if (cd
&& (cd
->IsOrig())) { // cell originates
2785 CellData
* cd2
= GetDataAt(rowIndex
, aColIndex
+1);
2786 if (cd2
&& cd2
->IsColSpan()) { // cd2 is spanned by a col
2787 if (cd
->GetCellFrame() == GetCellFrame(rowIndex
, aColIndex
+ 1, *cd2
, PR_FALSE
)) {
2796 void nsCellMap::DestroyCellData(CellData
* aData
)
2803 BCCellData
* bcData
= static_cast<BCCellData
*>(aData
);
2804 bcData
->~BCCellData();
2805 mPresContext
->FreeToShell(sizeof(BCCellData
), bcData
);
2808 mPresContext
->FreeToShell(sizeof(CellData
), aData
);
2812 CellData
* nsCellMap::AllocCellData(nsTableCellFrame
* aOrigCell
)
2815 BCCellData
* data
= (BCCellData
*)
2816 mPresContext
->AllocateFromShell(sizeof(BCCellData
));
2818 new (data
) BCCellData(aOrigCell
);
2823 CellData
* data
= (CellData
*)
2824 mPresContext
->AllocateFromShell(sizeof(CellData
));
2826 new (data
) CellData(aOrigCell
);
2832 nsCellMapColumnIterator::AdvanceRowGroup()
2835 mCurMapStart
+= mCurMapContentRowCount
;
2836 mCurMap
= mCurMap
->GetNextSibling();
2838 // Set mCurMapContentRowCount and mCurMapRelevantRowCount to 0 in case
2839 // mCurMap has no next sibling. This can happen if we just handled the
2840 // last originating cell. Future calls will end up with mFoundCells ==
2841 // mOrigCells, but for this one mFoundCells was definitely not big enough
2843 mCurMapContentRowCount
= 0;
2844 mCurMapRelevantRowCount
= 0;
2848 mCurMapContentRowCount
= mCurMap
->GetRowCount();
2849 PRUint32 rowArrayLength
= mCurMap
->mRows
.Length();
2850 mCurMapRelevantRowCount
= NS_MIN(mCurMapContentRowCount
, rowArrayLength
);
2851 } while (0 == mCurMapRelevantRowCount
);
2853 NS_ASSERTION(mCurMapRelevantRowCount
!= 0 || !mCurMap
,
2854 "How did that happen?");
2856 // Set mCurMapRow to 0, since cells can't span across table row groups.
2861 nsCellMapColumnIterator::IncrementRow(PRInt32 aIncrement
)
2863 NS_PRECONDITION(aIncrement
>= 0, "Bogus increment");
2864 NS_PRECONDITION(mCurMap
, "Bogus mOrigCells?");
2865 if (aIncrement
== 0) {
2869 mCurMapRow
+= aIncrement
;
2870 if (mCurMapRow
>= mCurMapRelevantRowCount
) {
2877 nsCellMapColumnIterator::GetNextFrame(PRInt32
* aRow
, PRInt32
* aColSpan
)
2879 // Fast-path for the case when we don't have anything left in the column and
2881 if (mFoundCells
== mOrigCells
) {
2888 NS_ASSERTION(mCurMapRow
< mCurMapRelevantRowCount
, "Bogus mOrigCells?");
2889 // Safe to just get the row (which is faster than calling GetDataAt(), but
2890 // there may not be that many cells in it, so have to use SafeElementAt for
2892 const nsCellMap::CellDataArray
& row
= mCurMap
->mRows
[mCurMapRow
];
2893 CellData
* cellData
= row
.SafeElementAt(mCol
);
2894 if (!cellData
|| cellData
->IsDead()) {
2895 // Could hit this if there are fewer cells in this row than others, for
2901 if (cellData
->IsColSpan()) {
2902 // Look up the originating data for this cell, advance by its relative rowspan.
2903 PRInt32 rowspanOffset
= cellData
->GetRowSpanOffset();
2904 nsTableCellFrame
* cellFrame
= mCurMap
->GetCellFrame(mCurMapRow
, mCol
, *cellData
, PR_FALSE
);
2905 NS_ASSERTION(cellFrame
,"Must have usable originating data here");
2906 PRInt32 rowSpan
= cellFrame
->GetRowSpan();
2911 IncrementRow(rowSpan
- rowspanOffset
);
2916 NS_ASSERTION(cellData
->IsOrig(),
2917 "Must have originating cellData by this point. "
2918 "See comment on mCurMapRow in header.");
2920 nsTableCellFrame
* cellFrame
= cellData
->GetCellFrame();
2921 NS_ASSERTION(cellFrame
, "Orig data without cellframe?");
2923 *aRow
= mCurMapStart
+ mCurMapRow
;
2924 PRBool ignoredZeroSpan
;
2925 *aColSpan
= mCurMap
->GetEffectiveColSpan(*mMap
, mCurMapRow
, mCol
,
2928 IncrementRow(cellFrame
->GetRowSpan());
2932 NS_ASSERTION(cellData
= mMap
->GetDataAt(*aRow
, mCol
),
2933 "Giving caller bogus row?");
2938 NS_NOTREACHED("Can't get here");