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 ***** */
38 #include "nsVoidArray.h"
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();
104 PRInt32 colCount
= mCols
.Count();
105 for (PRInt32 colX
= 0; colX
< colCount
; colX
++) {
106 nsColInfo
* colInfo
= (nsColInfo
*)mCols
.ElementAt(colX
);
112 DeleteRightBottomBorders();
117 // Get the bcData holding the border segments of the right edge of the table
119 nsTableCellMap::GetRightMostBorder(PRInt32 aRowIndex
)
121 if (!mBCInfo
) ABORT1(nsnull
);
123 PRInt32 numRows
= mBCInfo
->mRightBorders
.Count();
124 if (aRowIndex
< numRows
) {
125 return (BCData
*)mBCInfo
->mRightBorders
.ElementAt(aRowIndex
);
129 PRInt32 rowX
= numRows
;
132 bcData
= new BCData();
133 if (!bcData
) ABORT1(nsnull
);
134 mBCInfo
->mRightBorders
.AppendElement(bcData
);
135 } while (++rowX
<= aRowIndex
);
140 // Get the bcData holding the border segments of the bottom edge of the table
142 nsTableCellMap::GetBottomMostBorder(PRInt32 aColIndex
)
144 if (!mBCInfo
) ABORT1(nsnull
);
146 PRInt32 numCols
= mBCInfo
->mBottomBorders
.Count();
147 if (aColIndex
< numCols
) {
148 return (BCData
*)mBCInfo
->mBottomBorders
.ElementAt(aColIndex
);
152 PRInt32 colX
= numCols
;
155 bcData
= new BCData();
156 if (!bcData
) ABORT1(nsnull
);
157 mBCInfo
->mBottomBorders
.AppendElement(bcData
);
158 } while (++colX
<= aColIndex
);
163 // delete the borders corresponding to the right and bottom edges of the table
165 nsTableCellMap::DeleteRightBottomBorders()
168 PRInt32 numCols
= mBCInfo
->mBottomBorders
.Count();
170 for (PRInt32 colX
= numCols
- 1; colX
>= 0; colX
--) {
171 BCData
* bcData
= (BCData
*)mBCInfo
->mBottomBorders
.ElementAt(colX
);
175 mBCInfo
->mBottomBorders
.RemoveElementAt(colX
);
178 PRUint32 numRows
= mBCInfo
->mRightBorders
.Count();
180 for (PRInt32 rowX
= numRows
- 1; rowX
>= 0; rowX
--) {
181 BCData
* bcData
= (BCData
*)mBCInfo
->mRightBorders
.ElementAt(rowX
);
185 mBCInfo
->mRightBorders
.RemoveElementAt(rowX
);
192 nsTableCellMap::InsertGroupCellMap(nsCellMap
* aPrevMap
,
197 next
= aPrevMap
->GetNextSibling();
198 aPrevMap
->SetNextSibling(&aNewMap
);
202 mFirstMap
= &aNewMap
;
204 aNewMap
.SetNextSibling(next
);
207 void nsTableCellMap::InsertGroupCellMap(nsTableRowGroupFrame
& aNewGroup
,
208 nsTableRowGroupFrame
*& aPrevGroup
)
210 nsCellMap
* newMap
= new nsCellMap(aNewGroup
, mBCInfo
!= nsnull
);
212 nsCellMap
* prevMap
= nsnull
;
213 nsCellMap
* lastMap
= mFirstMap
;
215 nsCellMap
* map
= mFirstMap
;
218 if (map
->GetRowGroup() == aPrevGroup
) {
222 map
= map
->GetNextSibling();
228 aPrevGroup
= (prevMap
) ? prevMap
->GetRowGroup() : nsnull
;
234 InsertGroupCellMap(prevMap
, *newMap
);
238 void nsTableCellMap::RemoveGroupCellMap(nsTableRowGroupFrame
* aGroup
)
240 nsCellMap
* map
= mFirstMap
;
241 nsCellMap
* prior
= nsnull
;
243 if (map
->GetRowGroup() == aGroup
) {
244 nsCellMap
* next
= map
->GetNextSibling();
245 if (mFirstMap
== map
) {
249 prior
->SetNextSibling(next
);
255 map
= map
->GetNextSibling();
260 FindMapFor(const nsTableRowGroupFrame
* aRowGroup
,
262 const nsCellMap
* aEnd
)
264 for (nsCellMap
* map
= aStart
; map
!= aEnd
; map
= map
->GetNextSibling()) {
265 if (aRowGroup
== map
->GetRowGroup()) {
274 nsTableCellMap::GetMapFor(const nsTableRowGroupFrame
* aRowGroup
,
275 nsCellMap
* aStartHint
) const
277 NS_PRECONDITION(aRowGroup
, "Must have a rowgroup");
278 NS_ASSERTION(!aRowGroup
->GetPrevInFlow(), "GetMapFor called with continuation");
280 nsCellMap
* map
= FindMapFor(aRowGroup
, aStartHint
, nsnull
);
286 nsCellMap
* map
= FindMapFor(aRowGroup
, mFirstMap
, aStartHint
);
291 // if aRowGroup is a repeated header or footer find the header or footer it was repeated from
292 if (aRowGroup
->IsRepeatable()) {
293 nsTableFrame
* fifTable
= static_cast<nsTableFrame
*>(mTableFrame
.GetFirstInFlow());
295 const nsStyleDisplay
* display
= aRowGroup
->GetStyleDisplay();
296 nsTableRowGroupFrame
* rgOrig
=
297 (NS_STYLE_DISPLAY_TABLE_HEADER_GROUP
== display
->mDisplay
) ?
298 fifTable
->GetTHead() : fifTable
->GetTFoot();
299 // find the row group cell map using the original header/footer
300 if (rgOrig
&& rgOrig
!= aRowGroup
) {
301 return GetMapFor(rgOrig
, aStartHint
);
309 nsTableCellMap::Synchronize(nsTableFrame
* aTableFrame
)
311 nsTableFrame::RowGroupArray orderedRowGroups
;
312 nsAutoTPtrArray
<nsCellMap
, 8> maps
;
314 aTableFrame
->OrderRowGroups(orderedRowGroups
);
315 if (!orderedRowGroups
.Length()) {
319 // XXXbz this fails if orderedRowGroups is missing some row groups
320 // (due to OOM when appending to the array, e.g. -- we leak maps in
323 // Scope |map| outside the loop so we can use it as a hint.
324 nsCellMap
* map
= nsnull
;
325 for (PRUint32 rgX
= 0; rgX
< orderedRowGroups
.Length(); rgX
++) {
326 nsTableRowGroupFrame
* rgFrame
= orderedRowGroups
[rgX
];
327 map
= GetMapFor((nsTableRowGroupFrame
*)rgFrame
->GetFirstInFlow(), map
);
329 if (!maps
.AppendElement(map
)) {
331 NS_WARNING("Could not AppendElement");
336 PRInt32 mapIndex
= maps
.Length() - 1; // Might end up -1
337 nsCellMap
* nextMap
= maps
.ElementAt(mapIndex
);
338 nextMap
->SetNextSibling(nsnull
);
339 for (mapIndex
-- ; mapIndex
>= 0; mapIndex
--) {
340 nsCellMap
* map
= maps
.ElementAt(mapIndex
);
341 map
->SetNextSibling(nextMap
);
348 nsTableCellMap::HasMoreThanOneCell(PRInt32 aRowIndex
) const
350 PRInt32 rowIndex
= aRowIndex
;
351 nsCellMap
* map
= mFirstMap
;
353 if (map
->GetRowCount() > rowIndex
) {
354 return map
->HasMoreThanOneCell(rowIndex
);
356 rowIndex
-= map
->GetRowCount();
357 map
= map
->GetNextSibling();
363 nsTableCellMap::GetNumCellsOriginatingInRow(PRInt32 aRowIndex
) const
365 PRInt32 rowIndex
= aRowIndex
;
366 nsCellMap
* map
= mFirstMap
;
368 if (map
->GetRowCount() > rowIndex
) {
369 return map
->GetNumCellsOriginatingInRow(rowIndex
);
371 rowIndex
-= map
->GetRowCount();
372 map
= map
->GetNextSibling();
377 nsTableCellMap::GetEffectiveRowSpan(PRInt32 aRowIndex
,
378 PRInt32 aColIndex
) const
380 PRInt32 rowIndex
= aRowIndex
;
381 nsCellMap
* map
= mFirstMap
;
383 if (map
->GetRowCount() > rowIndex
) {
384 return map
->GetRowSpan(rowIndex
, aColIndex
, PR_TRUE
);
386 rowIndex
-= map
->GetRowCount();
387 map
= map
->GetNextSibling();
389 NS_NOTREACHED("Bogus row index?");
394 nsTableCellMap::GetEffectiveColSpan(PRInt32 aRowIndex
,
395 PRInt32 aColIndex
) const
397 PRInt32 rowIndex
= aRowIndex
;
398 nsCellMap
* map
= mFirstMap
;
400 if (map
->GetRowCount() > rowIndex
) {
402 return map
->GetEffectiveColSpan(*this, rowIndex
, aColIndex
, zeroColSpan
);
404 rowIndex
-= map
->GetRowCount();
405 map
= map
->GetNextSibling();
407 NS_NOTREACHED("Bogus row index?");
412 nsTableCellMap::GetCellFrame(PRInt32 aRowIndex
,
415 PRBool aUseRowIfOverlap
) const
417 PRInt32 rowIndex
= aRowIndex
;
418 nsCellMap
* map
= mFirstMap
;
420 if (map
->GetRowCount() > rowIndex
) {
421 return map
->GetCellFrame(rowIndex
, aColIndex
, aData
, aUseRowIfOverlap
);
423 rowIndex
-= map
->GetRowCount();
424 map
= map
->GetNextSibling();
430 nsTableCellMap::GetColInfoAt(PRInt32 aColIndex
)
432 PRInt32 numColsToAdd
= aColIndex
+ 1 - mCols
.Count();
433 if (numColsToAdd
> 0) {
434 AddColsAtEnd(numColsToAdd
); // XXX this could fail to add cols in theory
436 return (nsColInfo
*)mCols
.ElementAt(aColIndex
);
440 nsTableCellMap::GetRowCount() const
443 nsCellMap
* map
= mFirstMap
;
445 numRows
+= map
->GetRowCount();
446 map
= map
->GetNextSibling();
452 nsTableCellMap::GetDataAt(PRInt32 aRowIndex
,
453 PRInt32 aColIndex
) const
455 PRInt32 rowIndex
= aRowIndex
;
456 nsCellMap
* map
= mFirstMap
;
458 if (map
->GetRowCount() > rowIndex
) {
459 return map
->GetDataAt(rowIndex
, aColIndex
);
461 rowIndex
-= map
->GetRowCount();
462 map
= map
->GetNextSibling();
468 nsTableCellMap::AddColsAtEnd(PRUint32 aNumCols
)
471 // XXX We really should have a way to say "make this voidarray at least
472 // N entries long" to avoid reallocating N times. On the other hand, the
473 // number of likely allocations here isn't TOO gigantic, and we may not
474 // know about many of them at a time.
475 for (PRUint32 numX
= 1; numX
<= aNumCols
; numX
++) {
476 nsColInfo
* colInfo
= new nsColInfo();
478 added
= mCols
.AppendElement(colInfo
);
481 NS_WARNING("Could not AppendElement");
485 BCData
* bcData
= new BCData();
487 added
= mBCInfo
->mBottomBorders
.AppendElement(bcData
);
490 NS_WARNING("Could not AppendElement");
498 nsTableCellMap::RemoveColsAtEnd()
500 // Remove the cols at the end which don't have originating cells or cells spanning
501 // into them. Only do this if the col was created as eColAnonymousCell
502 PRInt32 numCols
= GetColCount();
503 PRInt32 lastGoodColIndex
= mTableFrame
.GetIndexOfLastRealCol();
504 for (PRInt32 colX
= numCols
- 1; (colX
>= 0) && (colX
> lastGoodColIndex
); colX
--) {
505 nsColInfo
* colInfo
= (nsColInfo
*)mCols
.ElementAt(colX
);
507 if ((colInfo
->mNumCellsOrig
<= 0) && (colInfo
->mNumCellsSpan
<= 0)) {
510 mCols
.RemoveElementAt(colX
);
513 PRInt32 count
= mBCInfo
->mBottomBorders
.Count();
515 BCData
* bcData
= (BCData
*)mBCInfo
->mBottomBorders
.ElementAt(colX
);
519 mBCInfo
->mBottomBorders
.RemoveElementAt(colX
);
523 else break; // only remove until we encounter the 1st valid one
526 NS_ERROR("null entry in column info array");
527 mCols
.RemoveElementAt(colX
);
533 nsTableCellMap::ClearCols()
535 PRInt32 numCols
= GetColCount();
536 for (PRInt32 colX
= numCols
- 1; (colX
>= 0);colX
--) {
537 nsColInfo
* colInfo
= (nsColInfo
*)mCols
.ElementAt(colX
);
539 mCols
.RemoveElementAt(colX
);
541 PRInt32 count
= mBCInfo
->mBottomBorders
.Count();
543 BCData
* bcData
= (BCData
*)mBCInfo
->mBottomBorders
.ElementAt(colX
);
547 mBCInfo
->mBottomBorders
.RemoveElementAt(colX
);
553 nsTableCellMap::InsertRows(nsTableRowGroupFrame
& aParent
,
555 PRInt32 aFirstRowIndex
,
556 PRBool aConsiderSpans
,
559 PRInt32 numNewRows
= aRows
.Count();
560 if ((numNewRows
<= 0) || (aFirstRowIndex
< 0)) ABORT0();
562 PRInt32 rowIndex
= aFirstRowIndex
;
563 nsCellMap
* cellMap
= mFirstMap
;
565 nsTableRowGroupFrame
* rg
= cellMap
->GetRowGroup();
566 if (rg
== &aParent
) {
567 cellMap
->InsertRows(*this, aRows
, rowIndex
, aConsiderSpans
, aDamageArea
);
568 aDamageArea
.y
= PR_MIN(aFirstRowIndex
, aDamageArea
.y
);
569 aDamageArea
.height
= PR_MAX(0, GetRowCount() - aDamageArea
.y
);
570 #ifdef DEBUG_TABLE_CELLMAP
571 Dump("after InsertRows");
575 PRInt32 count
= mBCInfo
->mRightBorders
.Count();
576 if (aFirstRowIndex
< count
) {
577 for (PRInt32 rowX
= aFirstRowIndex
; rowX
< aFirstRowIndex
+ numNewRows
; rowX
++) {
578 bcData
= new BCData(); if (!bcData
) ABORT0();
579 mBCInfo
->mRightBorders
.InsertElementAt(bcData
, rowX
);
583 GetRightMostBorder(aFirstRowIndex
); // this will create missing entries
584 for (PRInt32 rowX
= aFirstRowIndex
+ 1; rowX
< aFirstRowIndex
+ numNewRows
; rowX
++) {
585 bcData
= new BCData(); if (!bcData
) ABORT0();
586 mBCInfo
->mRightBorders
.AppendElement(bcData
);
592 rowIndex
-= cellMap
->GetRowCount();
593 cellMap
= cellMap
->GetNextSibling();
596 NS_ERROR("Attempt to insert row into wrong map.");
600 nsTableCellMap::RemoveRows(PRInt32 aFirstRowIndex
,
601 PRInt32 aNumRowsToRemove
,
602 PRBool aConsiderSpans
,
605 PRInt32 rowIndex
= aFirstRowIndex
;
606 nsCellMap
* cellMap
= mFirstMap
;
608 if (cellMap
->GetRowCount() > rowIndex
) {
609 cellMap
->RemoveRows(*this, rowIndex
, aNumRowsToRemove
, aConsiderSpans
, aDamageArea
);
610 nsTableRowGroupFrame
* rg
= cellMap
->GetRowGroup();
611 aDamageArea
.y
+= (rg
) ? rg
->GetStartRowIndex() : 0;
612 aDamageArea
.height
= PR_MAX(0, GetRowCount() - aFirstRowIndex
);
615 for (PRInt32 rowX
= aFirstRowIndex
+ aNumRowsToRemove
- 1; rowX
>= aFirstRowIndex
; rowX
--) {
616 if (rowX
< mBCInfo
->mRightBorders
.Count()) {
617 bcData
= (BCData
*)mBCInfo
->mRightBorders
.ElementAt(rowX
);
621 mBCInfo
->mRightBorders
.RemoveElementAt(rowX
);
627 rowIndex
-= cellMap
->GetRowCount();
628 cellMap
= cellMap
->GetNextSibling();
630 #ifdef DEBUG_TABLE_CELLMAP
631 Dump("after RemoveRows");
638 nsTableCellMap::AppendCell(nsTableCellFrame
& aCellFrame
,
640 PRBool aRebuildIfNecessary
,
643 NS_ASSERTION(&aCellFrame
== aCellFrame
.GetFirstInFlow(), "invalid call on continuing frame");
644 nsIFrame
* rgFrame
= aCellFrame
.GetParent(); // get the row
645 if (!rgFrame
) return 0;
646 rgFrame
= rgFrame
->GetParent(); // get the row group
647 if (!rgFrame
) return 0;
649 CellData
* result
= nsnull
;
650 PRInt32 rowIndex
= aRowIndex
;
651 nsCellMap
* cellMap
= mFirstMap
;
653 if (cellMap
->GetRowGroup() == rgFrame
) {
654 result
= cellMap
->AppendCell(*this, &aCellFrame
, rowIndex
, aRebuildIfNecessary
, aDamageArea
);
655 nsTableRowGroupFrame
* rg
= cellMap
->GetRowGroup();
656 aDamageArea
.y
+= (rg
) ? rg
->GetStartRowIndex() : 0;
659 rowIndex
-= cellMap
->GetRowCount();
660 cellMap
= cellMap
->GetNextSibling();
662 #ifdef DEBUG_TABLE_CELLMAP
663 Dump("after AppendCell");
670 nsTableCellMap::InsertCells(nsVoidArray
& aCellFrames
,
672 PRInt32 aColIndexBefore
,
675 PRInt32 rowIndex
= aRowIndex
;
676 nsCellMap
* cellMap
= mFirstMap
;
678 if (cellMap
->GetRowCount() > rowIndex
) {
679 cellMap
->InsertCells(*this, aCellFrames
, rowIndex
, aColIndexBefore
, aDamageArea
);
680 nsTableRowGroupFrame
* rg
= cellMap
->GetRowGroup();
681 aDamageArea
.y
+= (rg
) ? rg
->GetStartRowIndex() : 0;
682 aDamageArea
.width
= PR_MAX(0, GetColCount() - aColIndexBefore
- 1);
685 rowIndex
-= cellMap
->GetRowCount();
686 cellMap
= cellMap
->GetNextSibling();
688 #ifdef DEBUG_TABLE_CELLMAP
689 Dump("after InsertCells");
695 nsTableCellMap::RemoveCell(nsTableCellFrame
* aCellFrame
,
699 if (!aCellFrame
) ABORT0();
700 NS_ASSERTION(aCellFrame
== (nsTableCellFrame
*)aCellFrame
->GetFirstInFlow(),
701 "invalid call on continuing frame");
702 PRInt32 rowIndex
= aRowIndex
;
703 nsCellMap
* cellMap
= mFirstMap
;
705 if (cellMap
->GetRowCount() > rowIndex
) {
706 cellMap
->RemoveCell(*this, aCellFrame
, rowIndex
, aDamageArea
);
707 nsTableRowGroupFrame
* rg
= cellMap
->GetRowGroup();
708 aDamageArea
.y
+= (rg
) ? rg
->GetStartRowIndex() : 0;
710 aCellFrame
->GetColIndex(colIndex
);
711 aDamageArea
.width
= PR_MAX(0, GetColCount() - colIndex
- 1);
712 #ifdef DEBUG_TABLE_CELLMAP
713 Dump("after RemoveCell");
717 rowIndex
-= cellMap
->GetRowCount();
718 cellMap
= cellMap
->GetNextSibling();
720 // if we reach this point - the cell did not get removed, the caller of this routine
721 // will delete the cell and the cellmap will probably hold a reference to
722 // the deleted cell which will cause a subsequent crash when this cell is
724 NS_ERROR("nsTableCellMap::RemoveCell - could not remove cell");
728 SetDamageArea(PRInt32 aXOrigin
,
734 aDamageArea
.x
= aXOrigin
;
735 aDamageArea
.y
= aYOrigin
;
736 aDamageArea
.width
= PR_MAX(1, aWidth
);
737 aDamageArea
.height
= PR_MAX(1, aHeight
);
741 nsTableCellMap::RebuildConsideringCells(nsCellMap
* aCellMap
,
742 nsVoidArray
* aCellFrames
,
748 PRInt32 numOrigCols
= GetColCount();
750 nsCellMap
* cellMap
= mFirstMap
;
751 PRInt32 rowCount
= 0;
753 if (cellMap
== aCellMap
) {
754 cellMap
->RebuildConsideringCells(*this, numOrigCols
, aCellFrames
, aRowIndex
, aColIndex
, aInsert
, aDamageArea
);
758 cellMap
->RebuildConsideringCells(*this, numOrigCols
, nsnull
, -1, 0, PR_FALSE
, aDamageArea
);
760 rowCount
+= cellMap
->GetRowCount();
761 cellMap
= cellMap
->GetNextSibling();
763 SetDamageArea(0, 0, GetColCount(), rowCount
, aDamageArea
);
767 nsTableCellMap::RebuildConsideringRows(nsCellMap
* aCellMap
,
768 PRInt32 aStartRowIndex
,
769 nsVoidArray
* aRowsToInsert
,
770 PRInt32 aNumRowsToRemove
,
773 NS_PRECONDITION(!aRowsToInsert
|| aNumRowsToRemove
== 0,
774 "Can't handle both removing and inserting rows at once");
776 PRInt32 numOrigCols
= GetColCount();
778 nsCellMap
* cellMap
= mFirstMap
;
779 PRInt32 rowCount
= 0;
781 if (cellMap
== aCellMap
) {
782 cellMap
->RebuildConsideringRows(*this, aStartRowIndex
, aRowsToInsert
, aNumRowsToRemove
, aDamageArea
);
785 cellMap
->RebuildConsideringCells(*this, numOrigCols
, nsnull
, -1, 0, PR_FALSE
, aDamageArea
);
787 rowCount
+= cellMap
->GetRowCount();
788 cellMap
= cellMap
->GetNextSibling();
790 SetDamageArea(0, 0, GetColCount(), rowCount
, aDamageArea
);
794 nsTableCellMap::GetNumCellsOriginatingInCol(PRInt32 aColIndex
) const
796 PRInt32 colCount
= mCols
.Count();
797 if ((aColIndex
>= 0) && (aColIndex
< colCount
)) {
798 return ((nsColInfo
*)mCols
.ElementAt(aColIndex
))->mNumCellsOrig
;
801 NS_ERROR("nsCellMap::GetNumCellsOriginatingInCol - bad col index");
808 nsTableCellMap::Dump(char* aString
) const
811 printf("%s \n", aString
);
812 printf("***** START TABLE CELL MAP DUMP ***** %p\n", (void*)this);
814 PRInt32 colCount
= mCols
.Count();
815 printf ("cols array orig/span-> %p", (void*)this);
816 for (PRInt32 colX
= 0; colX
< colCount
; colX
++) {
817 nsColInfo
* colInfo
= (nsColInfo
*)mCols
.ElementAt(colX
);
818 printf ("%d=%d/%d ", colX
, colInfo
->mNumCellsOrig
, colInfo
->mNumCellsSpan
);
820 printf(" cols in cache %d\n", mTableFrame
.GetColCache().Count());
821 nsCellMap
* cellMap
= mFirstMap
;
823 cellMap
->Dump(nsnull
!= mBCInfo
);
824 cellMap
= cellMap
->GetNextSibling();
826 if (nsnull
!= mBCInfo
) {
827 printf("***** bottom borders *****\n");
834 PRInt32 numCols
= mBCInfo
->mBottomBorders
.Count();
835 for (PRInt32 i
= 0; i
<= 2; i
++) {
838 for (colIndex
= 0; colIndex
< numCols
; colIndex
++) {
839 BCData
* cd
= (BCData
*)mBCInfo
->mBottomBorders
.ElementAt(colIndex
);;
842 size
= cd
->GetTopEdge(owner
, segStart
);
843 printf("t=%d%X%d ", size
, owner
, segStart
);
846 size
= cd
->GetLeftEdge(owner
, segStart
);
847 printf("l=%d%X%d ", size
, owner
, segStart
);
850 size
= cd
->GetCorner(side
, bevel
);
851 printf("c=%d%X%d ", size
, side
, bevel
);
855 BCData
* cd
= &mBCInfo
->mLowerRightCorner
;
858 size
= cd
->GetTopEdge(owner
, segStart
);
859 printf("t=%d%X%d ", size
, owner
, segStart
);
862 size
= cd
->GetLeftEdge(owner
, segStart
);
863 printf("l=%d%X%d ", size
, owner
, segStart
);
866 size
= cd
->GetCorner(side
, bevel
);
867 printf("c=%d%X%d ", size
, side
, bevel
);
873 printf("***** END TABLE CELL MAP DUMP *****\n");
878 nsTableCellMap::GetCellInfoAt(PRInt32 aRowIndex
,
881 PRInt32
* aColSpan
) const
883 PRInt32 rowIndex
= aRowIndex
;
884 nsCellMap
* cellMap
= mFirstMap
;
886 if (cellMap
->GetRowCount() > rowIndex
) {
887 return cellMap
->GetCellInfoAt(*this, rowIndex
, aColIndex
, aOriginates
, aColSpan
);
889 rowIndex
-= cellMap
->GetRowCount();
890 cellMap
= cellMap
->GetNextSibling();
896 nsTableCellMap::GetIndexByRowAndColumn(PRInt32 aRow
, PRInt32 aColumn
) const
900 PRInt32 colCount
= mCols
.Count();
901 PRInt32 rowIndex
= aRow
;
903 nsCellMap
* cellMap
= mFirstMap
;
905 PRInt32 rowCount
= cellMap
->GetRowCount();
906 if (rowIndex
>= rowCount
) {
907 // If the rowCount is less than the rowIndex, this means that the index is
908 // not within the current map. If so, get the index of the last cell in
910 PRInt32 cellMapIdx
= cellMap
->GetIndexByRowAndColumn(colCount
,
913 if (cellMapIdx
!= -1) {
914 index
+= cellMapIdx
+ 1;
915 rowIndex
-= rowCount
;
918 // Index is in valid range for this cellmap, so get the index of rowIndex
920 PRInt32 cellMapIdx
= cellMap
->GetIndexByRowAndColumn(colCount
, rowIndex
,
922 if (cellMapIdx
!= -1) {
924 return index
; // no need to look through further maps here
928 cellMap
= cellMap
->GetNextSibling();
935 nsTableCellMap::GetRowAndColumnByIndex(PRInt32 aIndex
,
936 PRInt32
*aRow
, PRInt32
*aColumn
) const
941 PRInt32 colCount
= mCols
.Count();
943 PRInt32 previousRows
= 0;
944 PRInt32 index
= aIndex
;
946 nsCellMap
* cellMap
= mFirstMap
;
948 PRInt32 rowCount
= cellMap
->GetRowCount();
949 // Determine the highest possible index in this map to see
950 // if wanted index is in here.
951 PRInt32 cellMapIdx
= cellMap
->GetIndexByRowAndColumn(colCount
,
954 if (cellMapIdx
!= -1) {
955 if (index
> cellMapIdx
) {
956 // The index is not within this map, so decrease it by the cellMapIdx
957 // determined index and increase the total row index accordingly.
958 index
-= cellMapIdx
+ 1;
959 previousRows
+= rowCount
;
961 cellMap
->GetRowAndColumnByIndex(colCount
, index
, aRow
, aColumn
);
962 // If there were previous indexes, take them into account.
963 *aRow
+= previousRows
;
964 return; // no need to look any further.
968 cellMap
= cellMap
->GetNextSibling();
972 PRBool
nsTableCellMap::RowIsSpannedInto(PRInt32 aRowIndex
,
973 PRInt32 aNumEffCols
) const
975 PRInt32 rowIndex
= aRowIndex
;
976 nsCellMap
* cellMap
= mFirstMap
;
978 if (cellMap
->GetRowCount() > rowIndex
) {
979 return cellMap
->RowIsSpannedInto(rowIndex
, aNumEffCols
);
981 rowIndex
-= cellMap
->GetRowCount();
982 cellMap
= cellMap
->GetNextSibling();
987 PRBool
nsTableCellMap::RowHasSpanningCells(PRInt32 aRowIndex
,
988 PRInt32 aNumEffCols
) const
990 PRInt32 rowIndex
= aRowIndex
;
991 nsCellMap
* cellMap
= mFirstMap
;
993 if (cellMap
->GetRowCount() > rowIndex
) {
994 return cellMap
->RowHasSpanningCells(rowIndex
, aNumEffCols
);
996 rowIndex
-= cellMap
->GetRowCount();
997 cellMap
= cellMap
->GetNextSibling();
1002 PRBool
nsTableCellMap::ColIsSpannedInto(PRInt32 aColIndex
) const
1004 PRBool result
= PR_FALSE
;
1006 PRInt32 colCount
= mCols
.Count();
1007 if ((aColIndex
>= 0) && (aColIndex
< colCount
)) {
1008 result
= ((nsColInfo
*)mCols
.ElementAt(aColIndex
))->mNumCellsSpan
!= 0;
1013 PRBool
nsTableCellMap::ColHasSpanningCells(PRInt32 aColIndex
) const
1015 NS_PRECONDITION (aColIndex
< GetColCount(), "bad col index arg");
1016 nsCellMap
* cellMap
= mFirstMap
;
1018 if (cellMap
->ColHasSpanningCells(aColIndex
)) {
1021 cellMap
= cellMap
->GetNextSibling();
1026 void nsTableCellMap::ExpandZeroColSpans()
1028 mTableFrame
.SetNeedColSpanExpansion(PR_FALSE
); // mark the work done
1029 mTableFrame
.SetHasZeroColSpans(PR_FALSE
); // reset the bit, if there is a
1030 // zerospan it will be set again.
1031 nsCellMap
* cellMap
= mFirstMap
;
1033 cellMap
->ExpandZeroColSpans(*this);
1034 cellMap
= cellMap
->GetNextSibling();
1038 nsTableCellMap::GetBCData(PRUint8 aSide
,
1039 nsCellMap
& aCellMap
,
1042 PRBool aIsLowerRight
)
1044 if (!mBCInfo
|| aIsLowerRight
) ABORT1(nsnull
);
1046 BCCellData
* cellData
;
1047 BCData
* bcData
= nsnull
;
1050 case NS_SIDE_BOTTOM
:
1053 cellData
= (BCCellData
*)aCellMap
.GetDataAt(aRowIndex
, aColIndex
);
1055 bcData
= &cellData
->mData
;
1058 NS_ASSERTION(aSide
== NS_SIDE_BOTTOM
, "program error");
1059 // try the next row group
1060 nsCellMap
* cellMap
= aCellMap
.GetNextSibling();
1062 cellData
= (BCCellData
*)cellMap
->GetDataAt(0, aColIndex
);
1064 bcData
= &cellData
->mData
;
1067 bcData
= GetBottomMostBorder(aColIndex
);
1075 cellData
= (BCCellData
*)aCellMap
.GetDataAt(aRowIndex
, aColIndex
);
1077 bcData
= &cellData
->mData
;
1080 NS_ASSERTION(aSide
== NS_SIDE_RIGHT
, "program error");
1081 bcData
= GetRightMostBorder(aRowIndex
);
1088 // store the aSide border segment at coord = (aRowIndex, aColIndex). For top/left, store
1089 // the info at coord. For bottom/left store it at the adjacent location so that it is
1090 // top/left at that location. If the new location is at the right or bottom edge of the
1091 // table, then store it one of the special arrays (right most borders, bottom most borders).
1093 nsTableCellMap::SetBCBorderEdge(PRUint8 aSide
,
1094 nsCellMap
& aCellMap
,
1095 PRUint32 aCellMapStart
,
1099 BCBorderOwner aOwner
,
1103 if (!mBCInfo
) ABORT0();
1105 BCCellData
* cellData
;
1106 PRInt32 lastIndex
, xIndex
, yIndex
;
1107 PRInt32 xPos
= aColIndex
;
1108 PRInt32 yPos
= aRowIndex
;
1109 PRInt32 rgYPos
= aRowIndex
- aCellMapStart
;
1113 case NS_SIDE_BOTTOM
:
1117 lastIndex
= xPos
+ aLength
- 1;
1118 for (xIndex
= xPos
; xIndex
<= lastIndex
; xIndex
++) {
1119 changed
= aChanged
&& (xIndex
== xPos
);
1120 BCData
* bcData
= nsnull
;
1121 cellData
= (BCCellData
*)aCellMap
.GetDataAt(rgYPos
, xIndex
);
1123 PRInt32 numRgRows
= aCellMap
.GetRowCount();
1124 if (yPos
< numRgRows
) { // add a dead cell data
1126 cellData
= (BCCellData
*)aCellMap
.AppendCell(*this, nsnull
, rgYPos
, PR_FALSE
, damageArea
); if (!cellData
) ABORT0();
1129 NS_ASSERTION(aSide
== NS_SIDE_BOTTOM
, "program error");
1130 // try the next non empty row group
1131 nsCellMap
* cellMap
= aCellMap
.GetNextSibling();
1132 while (cellMap
&& (0 == cellMap
->GetRowCount())) {
1133 cellMap
= cellMap
->GetNextSibling();
1136 cellData
= (BCCellData
*)cellMap
->GetDataAt(0, xIndex
);
1137 if (!cellData
) { // add a dead cell
1139 cellData
= (BCCellData
*)cellMap
->AppendCell(*this, nsnull
, 0, PR_FALSE
, damageArea
);
1142 else { // must be at the end of the table
1143 bcData
= GetBottomMostBorder(xIndex
);
1147 if (!bcData
&& cellData
) {
1148 bcData
= &cellData
->mData
;
1151 bcData
->SetTopEdge(aOwner
, aSize
, changed
);
1153 else NS_ERROR("Cellmap: Top edge not found");
1159 // since top, bottom borders were set, there should already be a cellData entry
1160 lastIndex
= rgYPos
+ aLength
- 1;
1161 for (yIndex
= rgYPos
; yIndex
<= lastIndex
; yIndex
++) {
1162 changed
= aChanged
&& (yIndex
== rgYPos
);
1163 cellData
= (BCCellData
*)aCellMap
.GetDataAt(yIndex
, xPos
);
1165 cellData
->mData
.SetLeftEdge(aOwner
, aSize
, changed
);
1168 NS_ASSERTION(aSide
== NS_SIDE_RIGHT
, "program error");
1169 BCData
* bcData
= GetRightMostBorder(yIndex
+ aCellMapStart
);
1171 bcData
->SetLeftEdge(aOwner
, aSize
, changed
);
1173 else NS_ERROR("Cellmap: Left edge not found");
1180 // store corner info (aOwner, aSubSize, aBevel). For aCorner = eTopLeft, store the info at
1181 // (aRowIndex, aColIndex). For eTopRight, store it in the entry to the right where
1182 // it would be top left. For eBottomRight, store it in the entry to the bottom. etc.
1184 nsTableCellMap::SetBCBorderCorner(Corner aCorner
,
1185 nsCellMap
& aCellMap
,
1186 PRUint32 aCellMapStart
,
1192 PRBool aIsBottomRight
)
1194 if (!mBCInfo
) ABORT0();
1196 if (aIsBottomRight
) {
1197 mBCInfo
->mLowerRightCorner
.SetCorner(aSubSize
, aOwner
, aBevel
);
1201 PRInt32 xPos
= aColIndex
;
1202 PRInt32 yPos
= aRowIndex
;
1203 PRInt32 rgYPos
= aRowIndex
- aCellMapStart
;
1205 if (eTopRight
== aCorner
) {
1208 else if (eBottomRight
== aCorner
) {
1213 else if (eBottomLeft
== aCorner
) {
1218 BCCellData
* cellData
= nsnull
;
1219 BCData
* bcData
= nsnull
;
1220 if (GetColCount() <= xPos
) {
1221 NS_ASSERTION(xPos
== GetColCount(), "program error");
1222 // at the right edge of the table as we checked the corner before
1223 NS_ASSERTION(!aIsBottomRight
, "should be handled before");
1224 bcData
= GetRightMostBorder(yPos
);
1227 cellData
= (BCCellData
*)aCellMap
.GetDataAt(rgYPos
, xPos
);
1229 PRInt32 numRgRows
= aCellMap
.GetRowCount();
1230 if (yPos
< numRgRows
) { // add a dead cell data
1232 cellData
= (BCCellData
*)aCellMap
.AppendCell(*this, nsnull
, rgYPos
, PR_FALSE
, damageArea
);
1235 // try the next non empty row group
1236 nsCellMap
* cellMap
= aCellMap
.GetNextSibling();
1237 while (cellMap
&& (0 == cellMap
->GetRowCount())) {
1238 cellMap
= cellMap
->GetNextSibling();
1241 cellData
= (BCCellData
*)cellMap
->GetDataAt(0, xPos
);
1242 if (!cellData
) { // add a dead cell
1244 cellData
= (BCCellData
*)cellMap
->AppendCell(*this, nsnull
, 0, PR_FALSE
, damageArea
);
1247 else { // must be a the bottom of the table
1248 bcData
= GetBottomMostBorder(xPos
);
1253 if (!bcData
&& cellData
) {
1254 bcData
= &cellData
->mData
;
1257 bcData
->SetCorner(aSubSize
, aOwner
, aBevel
);
1259 else NS_ERROR("program error: Corner not found");
1262 nsCellMap::nsCellMap(nsTableRowGroupFrame
& aRowGroup
, PRBool aIsBC
)
1263 : mRows(8), mContentRowCount(0), mRowGroupFrame(&aRowGroup
),
1264 mNextSibling(nsnull
), mIsBC(aIsBC
),
1265 mPresContext(aRowGroup
.PresContext())
1267 MOZ_COUNT_CTOR(nsCellMap
);
1268 NS_ASSERTION(mPresContext
, "Must have prescontext");
1271 nsCellMap::~nsCellMap()
1273 MOZ_COUNT_DTOR(nsCellMap
);
1275 PRUint32 mapRowCount
= mRows
.Length();
1276 for (PRUint32 rowX
= 0; rowX
< mapRowCount
; rowX
++) {
1277 CellDataArray
&row
= mRows
[rowX
];
1278 PRUint32 colCount
= row
.Length();
1279 for (PRUint32 colX
= 0; colX
< colCount
; colX
++) {
1280 DestroyCellData(row
[colX
]);
1289 NS_ASSERTION(!sEmptyRow
, "How did that happen?");
1290 sEmptyRow
= new nsCellMap::CellDataArray();
1291 NS_ENSURE_TRUE(sEmptyRow
, NS_ERROR_OUT_OF_MEMORY
);
1298 nsCellMap::Shutdown()
1305 nsCellMap::GetCellFrame(PRInt32 aRowIndexIn
,
1306 PRInt32 aColIndexIn
,
1308 PRBool aUseRowIfOverlap
) const
1310 PRInt32 rowIndex
= aRowIndexIn
- aData
.GetRowSpanOffset();
1311 PRInt32 colIndex
= aColIndexIn
- aData
.GetColSpanOffset();
1312 if (aData
.IsOverlap()) {
1313 if (aUseRowIfOverlap
) {
1314 colIndex
= aColIndexIn
;
1317 rowIndex
= aRowIndexIn
;
1322 mRows
.SafeElementAt(rowIndex
, *sEmptyRow
).SafeElementAt(colIndex
);
1324 return data
->GetCellFrame();
1330 nsCellMap::GetIndexByRowAndColumn(PRInt32 aColCount
,
1331 PRInt32 aRow
, PRInt32 aColumn
) const
1335 if (aRow
>= mRows
.Length())
1338 PRInt32 lastColsIdx
= aColCount
- 1;
1339 for (PRInt32 rowIdx
= 0; rowIdx
<= aRow
; rowIdx
++) {
1340 const CellDataArray
& row
= mRows
[rowIdx
];
1341 PRInt32 colCount
= (rowIdx
== aRow
) ? aColumn
: lastColsIdx
;
1343 for (PRInt32 colIdx
= 0; colIdx
<= colCount
; colIdx
++) {
1344 CellData
* data
= row
.SafeElementAt(colIdx
);
1345 if (data
&& data
->IsOrig())
1354 nsCellMap::GetRowAndColumnByIndex(PRInt32 aColCount
, PRInt32 aIndex
,
1355 PRInt32
*aRow
, PRInt32
*aColumn
) const
1360 PRInt32 index
= aIndex
;
1361 PRInt32 rowCount
= mRows
.Length();
1363 for (PRInt32 rowIdx
= 0; rowIdx
< rowCount
; rowIdx
++) {
1364 const CellDataArray
& row
= mRows
[rowIdx
];
1366 for (PRInt32 colIdx
= 0; colIdx
< aColCount
; colIdx
++) {
1367 CellData
* data
= row
.SafeElementAt(colIdx
);
1368 if (data
&& data
->IsOrig())
1380 PRBool
nsCellMap::Grow(nsTableCellMap
& aMap
,
1384 NS_ASSERTION(aNumRows
>= 1, "Why are we calling this?");
1386 // Get the number of cols we want to use for preallocating the row arrays.
1387 PRInt32 numCols
= aMap
.GetColCount();
1391 PRUint32 startRowIndex
= (aRowIndex
>= 0) ? aRowIndex
: mRows
.Length();
1392 NS_ASSERTION(startRowIndex
<= mRows
.Length(), "Missing grow call inbetween");
1394 return mRows
.InsertElementsAt(startRowIndex
, aNumRows
, numCols
) != nsnull
;
1397 void nsCellMap::GrowRow(CellDataArray
& aRow
,
1401 // Have to have the cast to get the template to do the right thing.
1402 aRow
.InsertElementsAt(aRow
.Length(), aNumCols
, (CellData
*)nsnull
);
1406 nsCellMap::InsertRows(nsTableCellMap
& aMap
,
1408 PRInt32 aFirstRowIndex
,
1409 PRBool aConsiderSpans
,
1410 nsRect
& aDamageArea
)
1412 PRInt32 numCols
= aMap
.GetColCount();
1413 NS_ASSERTION(aFirstRowIndex
>= 0, "nsCellMap::InsertRows called with negative rowIndex");
1414 if (PRUint32(aFirstRowIndex
) > mRows
.Length()) {
1415 // create (aFirstRowIndex - mRows.Length()) empty rows up to aFirstRowIndex
1416 PRInt32 numEmptyRows
= aFirstRowIndex
- mRows
.Length();
1417 if (!Grow(aMap
, numEmptyRows
)) {
1422 if (!aConsiderSpans
) {
1423 // update mContentRowCount, since non-empty rows will be added
1424 mContentRowCount
= PR_MAX(aFirstRowIndex
, mContentRowCount
);
1425 ExpandWithRows(aMap
, aRows
, aFirstRowIndex
, aDamageArea
);
1429 // if any cells span into or out of the row being inserted, then rebuild
1430 PRBool spansCauseRebuild
= CellsSpanInOrOut(aFirstRowIndex
,
1431 aFirstRowIndex
, 0, numCols
- 1);
1433 // update mContentRowCount, since non-empty rows will be added
1434 mContentRowCount
= PR_MAX(aFirstRowIndex
, mContentRowCount
);
1436 // if any of the new cells span out of the new rows being added, then rebuild
1437 // XXX it would be better to only rebuild the portion of the map that follows the new rows
1438 if (!spansCauseRebuild
&& (PRUint32(aFirstRowIndex
) < mRows
.Length())) {
1439 spansCauseRebuild
= CellsSpanOut(aRows
);
1442 if (spansCauseRebuild
) {
1443 aMap
.RebuildConsideringRows(this, aFirstRowIndex
, &aRows
, 0, aDamageArea
);
1446 ExpandWithRows(aMap
, aRows
, aFirstRowIndex
, aDamageArea
);
1451 nsCellMap::RemoveRows(nsTableCellMap
& aMap
,
1452 PRInt32 aFirstRowIndex
,
1453 PRInt32 aNumRowsToRemove
,
1454 PRBool aConsiderSpans
,
1455 nsRect
& aDamageArea
)
1457 PRInt32 numRows
= mRows
.Length();
1458 PRInt32 numCols
= aMap
.GetColCount();
1460 if (aFirstRowIndex
>= numRows
) {
1461 // reduce the content based row count based on the function arguments
1462 // as they are known to be real rows even if the cell map did not create
1463 // rows for them before.
1464 mContentRowCount
-= aNumRowsToRemove
;
1467 if (!aConsiderSpans
) {
1468 ShrinkWithoutRows(aMap
, aFirstRowIndex
, aNumRowsToRemove
, aDamageArea
);
1471 PRInt32 endRowIndex
= aFirstRowIndex
+ aNumRowsToRemove
- 1;
1472 if (endRowIndex
>= numRows
) {
1473 NS_ERROR("nsCellMap::RemoveRows tried to remove too many rows");
1474 endRowIndex
= numRows
- 1;
1476 PRBool spansCauseRebuild
= CellsSpanInOrOut(aFirstRowIndex
, endRowIndex
,
1479 if (spansCauseRebuild
) {
1480 aMap
.RebuildConsideringRows(this, aFirstRowIndex
, nsnull
, aNumRowsToRemove
, aDamageArea
);
1483 ShrinkWithoutRows(aMap
, aFirstRowIndex
, aNumRowsToRemove
, aDamageArea
);
1491 nsCellMap::AppendCell(nsTableCellMap
& aMap
,
1492 nsTableCellFrame
* aCellFrame
,
1494 PRBool aRebuildIfNecessary
,
1495 nsRect
& aDamageArea
,
1496 PRInt32
* aColToBeginSearch
)
1498 NS_ASSERTION(!!aMap
.mBCInfo
== mIsBC
, "BC state mismatch");
1499 PRInt32 origNumMapRows
= mRows
.Length();
1500 PRInt32 origNumCols
= aMap
.GetColCount();
1501 PRBool zeroRowSpan
= PR_FALSE
;
1502 PRInt32 rowSpan
= (aCellFrame
) ? GetRowSpanForNewCell(aCellFrame
, aRowIndex
,
1504 // add new rows if necessary
1505 PRInt32 endRowIndex
= aRowIndex
+ rowSpan
- 1;
1506 if (endRowIndex
>= origNumMapRows
) {
1507 // XXXbz handle allocation failures?
1508 Grow(aMap
, 1 + endRowIndex
- origNumMapRows
);
1511 // get the first null or dead CellData in the desired row. It will equal origNumCols if there are none
1512 CellData
* origData
= nsnull
;
1513 PRInt32 startColIndex
= 0;
1514 if (aColToBeginSearch
)
1515 startColIndex
= *aColToBeginSearch
;
1516 for (; startColIndex
< origNumCols
; startColIndex
++) {
1517 CellData
* data
= GetDataAt(aRowIndex
, startColIndex
);
1520 if (data
->IsDead()) {
1524 if (data
->IsZeroColSpan() ) {
1525 // appending a cell collapses zerospans.
1526 CollapseZeroColSpan(aMap
, data
, aRowIndex
, startColIndex
);
1527 // ask again for the data as it should be modified
1528 origData
= GetDataAt(aRowIndex
, startColIndex
);
1529 NS_ASSERTION(origData
->IsDead(),
1530 "The cellposition should have been cleared");
1534 // We found the place to append the cell, when the next cell is appended
1535 // the next search does not need to duplicate the search but can start
1536 // just at the next cell.
1537 if (aColToBeginSearch
)
1538 *aColToBeginSearch
= startColIndex
+ 1;
1540 PRBool zeroColSpan
= PR_FALSE
;
1541 PRInt32 colSpan
= (aCellFrame
) ?
1542 GetColSpanForNewCell(*aCellFrame
, zeroColSpan
) : 1;
1544 aMap
.mTableFrame
.SetHasZeroColSpans(PR_TRUE
);
1545 aMap
.mTableFrame
.SetNeedColSpanExpansion(PR_TRUE
);
1548 // if the new cell could potentially span into other rows and collide with
1549 // originating cells there, we will play it safe and just rebuild the map
1550 if (aRebuildIfNecessary
&& (aRowIndex
< mContentRowCount
- 1) && (rowSpan
> 1)) {
1551 nsAutoVoidArray newCellArray
;
1552 newCellArray
.AppendElement(aCellFrame
);
1553 aMap
.RebuildConsideringCells(this, &newCellArray
, aRowIndex
, startColIndex
, PR_TRUE
, aDamageArea
);
1556 mContentRowCount
= PR_MAX(mContentRowCount
, aRowIndex
+ 1);
1558 // add new cols to the table map if necessary
1559 PRInt32 endColIndex
= startColIndex
+ colSpan
- 1;
1560 if (endColIndex
>= origNumCols
) {
1561 NS_ASSERTION(aCellFrame
, "dead cells should not require new columns");
1562 aMap
.AddColsAtEnd(1 + endColIndex
- origNumCols
);
1565 // Setup CellData for this cell
1567 NS_ASSERTION(origData
->IsDead(), "replacing a non dead cell is a memory leak");
1568 if (aCellFrame
) { // do nothing to replace a dead cell with a dead cell
1569 origData
->Init(aCellFrame
);
1570 // we are replacing a dead cell, increase the number of cells
1571 // originating at this column
1572 nsColInfo
* colInfo
= aMap
.GetColInfoAt(startColIndex
);
1573 NS_ASSERTION(colInfo
, "access to a non existing column");
1575 colInfo
->mNumCellsOrig
++;
1580 origData
= AllocCellData(aCellFrame
);
1581 if (!origData
) ABORT1(origData
);
1582 SetDataAt(aMap
, *origData
, aRowIndex
, startColIndex
);
1585 SetDamageArea(startColIndex
, aRowIndex
, 1 + endColIndex
- startColIndex
, 1 + endRowIndex
- aRowIndex
, aDamageArea
);
1591 // initialize the cell frame
1592 aCellFrame
->SetColIndex(startColIndex
);
1594 // Create CellData objects for the rows that this cell spans. Set
1595 // their mOrigCell to nsnull and their mSpanData to point to data.
1596 for (PRInt32 rowX
= aRowIndex
; rowX
<= endRowIndex
; rowX
++) {
1597 // The row at rowX will need to have at least endColIndex columns
1598 mRows
[rowX
].SetCapacity(endColIndex
);
1599 for (PRInt32 colX
= startColIndex
; colX
<= endColIndex
; colX
++) {
1600 if ((rowX
!= aRowIndex
) || (colX
!= startColIndex
)) { // skip orig cell data done above
1601 CellData
* cellData
= GetDataAt(rowX
, colX
);
1603 if (cellData
->IsOrig()) {
1604 NS_ERROR("cannot overlap originating cell");
1607 if (rowX
> aRowIndex
) { // row spanning into cell
1608 if (cellData
->IsRowSpan()) {
1609 // do nothing, this can be caused by rowspan which is overlapped
1610 // by a another cell with a rowspan and a colspan
1613 cellData
->SetRowSpanOffset(rowX
- aRowIndex
);
1615 cellData
->SetZeroRowSpan(PR_TRUE
);
1619 if (colX
> startColIndex
) { // col spanning into cell
1620 if (!cellData
->IsColSpan()) {
1621 if (cellData
->IsRowSpan()) {
1622 cellData
->SetOverlap(PR_TRUE
);
1624 cellData
->SetColSpanOffset(colX
- startColIndex
);
1626 cellData
->SetZeroColSpan(PR_TRUE
);
1629 nsColInfo
* colInfo
= aMap
.GetColInfoAt(colX
);
1630 colInfo
->mNumCellsSpan
++;
1635 cellData
= AllocCellData(nsnull
);
1636 if (!cellData
) return origData
;
1637 if (rowX
> aRowIndex
) {
1638 cellData
->SetRowSpanOffset(rowX
- aRowIndex
);
1640 cellData
->SetZeroRowSpan(PR_TRUE
);
1643 if (colX
> startColIndex
) {
1644 cellData
->SetColSpanOffset(colX
- startColIndex
);
1646 cellData
->SetZeroColSpan(PR_TRUE
);
1649 SetDataAt(aMap
, *cellData
, rowX
, colX
);
1654 #ifdef DEBUG_TABLE_CELLMAP
1655 printf("appended cell=%p row=%d \n", aCellFrame
, aRowIndex
);
1661 void nsCellMap::CollapseZeroColSpan(nsTableCellMap
& aMap
,
1662 CellData
* aOrigData
,
1666 // if after a colspan = 0 cell another cell is appended in a row the html 4
1667 // spec is already violated. In principle one should then append the cell
1668 // after the last column but then the zero spanning cell would also have
1669 // to grow. The only plausible way to break this cycle is ignore the zero
1670 // colspan and reset the cell to colspan = 1.
1672 NS_ASSERTION(aOrigData
&& aOrigData
->IsZeroColSpan(),
1673 "zero colspan should have been passed");
1674 // find the originating cellframe
1675 nsTableCellFrame
* cell
= GetCellFrame(aRowIndex
, aColIndex
, *aOrigData
, PR_TRUE
);
1676 NS_ASSERTION(cell
, "originating cell not found");
1678 // find the clearing region
1679 PRInt32 startRowIndex
= aRowIndex
- aOrigData
->GetRowSpanOffset();
1681 PRInt32 rowSpan
= GetRowSpanForNewCell(cell
, startRowIndex
, zeroSpan
);
1682 PRInt32 endRowIndex
= startRowIndex
+ rowSpan
;
1684 PRInt32 origColIndex
= aColIndex
- aOrigData
->GetColSpanOffset();
1685 PRInt32 endColIndex
= origColIndex
+
1686 GetEffectiveColSpan(aMap
, startRowIndex
,
1687 origColIndex
, zeroSpan
);
1688 for (PRInt32 colX
= origColIndex
+1; colX
< endColIndex
; colX
++) {
1689 // Start the collapse just after the originating cell, since
1690 // we're basically making the originating cell act as if it
1692 nsColInfo
* colInfo
= aMap
.GetColInfoAt(colX
);
1693 colInfo
->mNumCellsSpan
-= rowSpan
;
1695 for (PRInt32 rowX
= startRowIndex
; rowX
< endRowIndex
; rowX
++)
1697 CellData
* data
= mRows
[rowX
][colX
];
1698 NS_ASSERTION(data
->IsZeroColSpan(),
1699 "Overwriting previous data - memory leak");
1700 data
->Init(nsnull
); // mark the cell as a dead cell.
1705 PRBool
nsCellMap::CellsSpanOut(nsVoidArray
& aRows
) const
1707 PRInt32 numNewRows
= aRows
.Count();
1708 for (PRInt32 rowX
= 0; rowX
< numNewRows
; rowX
++) {
1709 nsIFrame
* rowFrame
= (nsIFrame
*) aRows
.ElementAt(rowX
);
1710 nsIFrame
* cellFrame
= rowFrame
->GetFirstChild(nsnull
);
1712 if (IS_TABLE_CELL(cellFrame
->GetType())) {
1714 PRInt32 rowSpan
= GetRowSpanForNewCell((nsTableCellFrame
*) cellFrame
,
1716 if (rowX
+ rowSpan
> numNewRows
) {
1720 cellFrame
= cellFrame
->GetNextSibling();
1726 // return PR_TRUE if any cells have rows spans into or out of the region
1727 // defined by the row and col indices or any cells have colspans into the region
1728 PRBool
nsCellMap::CellsSpanInOrOut(PRInt32 aStartRowIndex
,
1729 PRInt32 aEndRowIndex
,
1730 PRInt32 aStartColIndex
,
1731 PRInt32 aEndColIndex
) const
1734 * this routine will watch the cells adjacent to the region or at the edge
1735 * they are marked with *. The routine will verify whether they span in or
1739 * r1c1 r1c2 r1c3 r1c4 r1c5 r1rc6 r1c7
1740 * startrow r2c1 r2c2 *r2c3 *r2c4 *r2c5 *r2rc6 r2c7
1741 * endrow r3c1 r3c2 *r3c3 r3c4 r3c5 *r3rc6 r3c7
1742 * r4c1 r4c2 *r4c3 *r4c4 *r4c5 r4rc6 r4c7
1743 * r5c1 r5c2 r5c3 r5c4 r5c5 r5rc6 r5c7
1746 PRInt32 numRows
= mRows
.Length(); // use the cellmap rows to determine the
1747 // current cellmap extent.
1748 for (PRInt32 colX
= aStartColIndex
; colX
<= aEndColIndex
; colX
++) {
1750 if (aStartRowIndex
> 0) {
1751 cellData
= GetDataAt(aStartRowIndex
, colX
);
1752 if (cellData
&& (cellData
->IsRowSpan())) {
1753 return PR_TRUE
; // there is a row span into the region
1755 if ((aStartRowIndex
>= mContentRowCount
) && (mContentRowCount
> 0)) {
1756 cellData
= GetDataAt(mContentRowCount
- 1, colX
);
1757 if (cellData
&& cellData
->IsZeroRowSpan()) {
1758 return PR_TRUE
; // When we expand the zerospan it'll span into our row
1762 if (aEndRowIndex
< numRows
- 1) { // is there anything below aEndRowIndex
1763 cellData
= GetDataAt(aEndRowIndex
+ 1, colX
);
1764 if ((cellData
) && (cellData
->IsRowSpan())) {
1765 return PR_TRUE
; // there is a row span out of the region
1769 cellData
= GetDataAt(aEndRowIndex
, colX
);
1770 if ((cellData
) && (cellData
->IsRowSpan()) && (mContentRowCount
< numRows
)) {
1771 return PR_TRUE
; // this cell might be the cause of a dead row
1775 if (aStartColIndex
> 0) {
1776 for (PRInt32 rowX
= aStartRowIndex
; rowX
<= aEndRowIndex
; rowX
++) {
1777 CellData
* cellData
= GetDataAt(rowX
, aStartColIndex
);
1778 if (cellData
&& (cellData
->IsColSpan())) {
1779 return PR_TRUE
; // there is a col span into the region
1781 cellData
= GetDataAt(rowX
, aEndColIndex
+ 1);
1782 if (cellData
&& (cellData
->IsColSpan())) {
1783 return PR_TRUE
; // there is a col span out of the region
1790 void nsCellMap::InsertCells(nsTableCellMap
& aMap
,
1791 nsVoidArray
& aCellFrames
,
1793 PRInt32 aColIndexBefore
,
1794 nsRect
& aDamageArea
)
1796 if (aCellFrames
.Count() == 0) return;
1797 NS_ASSERTION(aColIndexBefore
>= -1, "index out of range");
1798 PRInt32 numCols
= aMap
.GetColCount();
1799 if (aColIndexBefore
>= numCols
) {
1800 NS_ERROR("Inserting instead of appending cells indicates a serious cellmap error");
1801 aColIndexBefore
= numCols
- 1;
1804 // get the starting col index of the 1st new cells
1805 PRInt32 startColIndex
;
1806 for (startColIndex
= aColIndexBefore
+ 1; startColIndex
< numCols
; startColIndex
++) {
1807 CellData
* data
= GetDataAt(aRowIndex
, startColIndex
);
1808 if (!data
|| data
->IsOrig() || data
->IsDead()) {
1809 // // Not a span. Stop.
1812 if (data
->IsZeroColSpan()) {
1813 // Zero colspans collapse. Stop in this case too.
1814 CollapseZeroColSpan(aMap
, data
, aRowIndex
, startColIndex
);
1819 // record whether inserted cells are going to cause complications due
1820 // to existing row spans, col spans or table sizing.
1821 PRBool spansCauseRebuild
= PR_FALSE
;
1823 // check that all cells have the same row span
1824 PRInt32 numNewCells
= aCellFrames
.Count();
1825 PRBool zeroRowSpan
= PR_FALSE
;
1826 PRInt32 rowSpan
= 0;
1827 for (PRInt32 cellX
= 0; cellX
< numNewCells
; cellX
++) {
1828 nsTableCellFrame
* cell
= (nsTableCellFrame
*) aCellFrames
.ElementAt(cellX
);
1829 PRInt32 rowSpan2
= GetRowSpanForNewCell(cell
, aRowIndex
, zeroRowSpan
);
1833 else if (rowSpan
!= rowSpan2
) {
1834 spansCauseRebuild
= PR_TRUE
;
1839 // check if the new cells will cause the table to add more rows
1840 if (!spansCauseRebuild
) {
1841 if (mRows
.Length() < PRUint32(aRowIndex
+ rowSpan
)) {
1842 spansCauseRebuild
= PR_TRUE
;
1846 if (!spansCauseRebuild
) {
1847 spansCauseRebuild
= CellsSpanInOrOut(aRowIndex
, aRowIndex
+ rowSpan
- 1,
1848 startColIndex
, numCols
- 1);
1851 if (spansCauseRebuild
) {
1852 aMap
.RebuildConsideringCells(this, &aCellFrames
, aRowIndex
, startColIndex
, PR_TRUE
, aDamageArea
);
1855 ExpandWithCells(aMap
, aCellFrames
, aRowIndex
, startColIndex
, rowSpan
, zeroRowSpan
, aDamageArea
);
1860 nsCellMap::ExpandWithRows(nsTableCellMap
& aMap
,
1861 nsVoidArray
& aRowFrames
,
1862 PRInt32 aStartRowIndexIn
,
1863 nsRect
& aDamageArea
)
1865 PRInt32 startRowIndex
= (aStartRowIndexIn
>= 0) ? aStartRowIndexIn
: 0;
1866 NS_ASSERTION(PRUint32(startRowIndex
) <= mRows
.Length(), "caller should have grown cellmap before");
1868 PRInt32 numNewRows
= aRowFrames
.Count();
1869 mContentRowCount
+= numNewRows
;
1871 PRInt32 endRowIndex
= startRowIndex
+ numNewRows
- 1;
1873 // shift the rows after startRowIndex down and insert empty rows that will
1874 // be filled via the AppendCell call below
1875 if (!Grow(aMap
, numNewRows
, startRowIndex
)) {
1880 PRInt32 newRowIndex
= 0;
1881 for (PRInt32 rowX
= startRowIndex
; rowX
<= endRowIndex
; rowX
++) {
1882 nsTableRowFrame
* rFrame
= (nsTableRowFrame
*)aRowFrames
.ElementAt(newRowIndex
);
1884 nsIFrame
* cFrame
= rFrame
->GetFirstChild(nsnull
);
1885 PRInt32 colIndex
= 0;
1887 if (IS_TABLE_CELL(cFrame
->GetType())) {
1888 AppendCell(aMap
, (nsTableCellFrame
*)cFrame
, rowX
, PR_FALSE
, aDamageArea
, &colIndex
);
1890 cFrame
= cFrame
->GetNextSibling();
1895 SetDamageArea(0, startRowIndex
, aMap
.GetColCount(), 1 + endRowIndex
- startRowIndex
, aDamageArea
);
1898 void nsCellMap::ExpandWithCells(nsTableCellMap
& aMap
,
1899 nsVoidArray
& aCellFrames
,
1902 PRInt32 aRowSpan
, // same for all cells
1903 PRBool aRowSpanIsZero
,
1904 nsRect
& aDamageArea
)
1906 NS_ASSERTION(!!aMap
.mBCInfo
== mIsBC
, "BC state mismatch");
1907 PRInt32 endRowIndex
= aRowIndex
+ aRowSpan
- 1;
1908 PRInt32 startColIndex
= aColIndex
;
1909 PRInt32 endColIndex
= aColIndex
;
1910 PRInt32 numCells
= aCellFrames
.Count();
1911 PRInt32 totalColSpan
= 0;
1913 // add cellData entries for the space taken up by the new cells
1914 for (PRInt32 cellX
= 0; cellX
< numCells
; cellX
++) {
1915 nsTableCellFrame
* cellFrame
= (nsTableCellFrame
*) aCellFrames
.ElementAt(cellX
);
1916 CellData
* origData
= AllocCellData(cellFrame
); // the originating cell
1917 if (!origData
) return;
1919 // set the starting and ending col index for the new cell
1920 PRBool zeroColSpan
= PR_FALSE
;
1921 PRInt32 colSpan
= GetColSpanForNewCell(*cellFrame
, zeroColSpan
);
1923 aMap
.mTableFrame
.SetHasZeroColSpans(PR_TRUE
);
1924 aMap
.mTableFrame
.SetNeedColSpanExpansion(PR_TRUE
);
1926 totalColSpan
+= colSpan
;
1928 endColIndex
= aColIndex
+ colSpan
- 1;
1931 startColIndex
= endColIndex
+ 1;
1932 endColIndex
= startColIndex
+ colSpan
- 1;
1935 // add the originating cell data and any cell data corresponding to row/col spans
1936 for (PRInt32 rowX
= aRowIndex
; rowX
<= endRowIndex
; rowX
++) {
1937 CellDataArray
& row
= mRows
[rowX
];
1938 // Pre-allocate all the cells we'll need in this array, setting
1940 // Have to have the cast to get the template to do the right thing.
1941 PRUint32 insertionIndex
= row
.Length();
1942 if (insertionIndex
> aColIndex
) {
1943 insertionIndex
= aColIndex
;
1945 if (!row
.InsertElementsAt(insertionIndex
, endColIndex
- insertionIndex
+ 1,
1946 (CellData
*)nsnull
) &&
1947 rowX
== aRowIndex
) {
1948 // Failed to insert the slots, and this is the very first row. That
1949 // means that we need to clean up |origData| before returning, since
1950 // the cellmap doesn't own it yet.
1951 DestroyCellData(origData
);
1955 for (PRInt32 colX
= aColIndex
; colX
<= endColIndex
; colX
++) {
1956 CellData
* data
= origData
;
1957 if ((rowX
!= aRowIndex
) || (colX
!= startColIndex
)) {
1958 data
= AllocCellData(nsnull
);
1960 if (rowX
> aRowIndex
) {
1961 data
->SetRowSpanOffset(rowX
- aRowIndex
);
1962 if (aRowSpanIsZero
) {
1963 data
->SetZeroRowSpan(PR_TRUE
);
1966 if (colX
> startColIndex
) {
1967 data
->SetColSpanOffset(colX
- startColIndex
);
1969 data
->SetZeroColSpan(PR_TRUE
);
1973 SetDataAt(aMap
, *data
, rowX
, colX
);
1976 cellFrame
->SetColIndex(startColIndex
);
1978 PRInt32 damageHeight
= PR_MIN(GetRowGroup()->GetRowCount() - aRowIndex
, aRowSpan
);
1979 SetDamageArea(aColIndex
, aRowIndex
, 1 + endColIndex
- aColIndex
, damageHeight
, aDamageArea
);
1983 // update the row and col info due to shifting
1984 for (rowX
= aRowIndex
; rowX
<= endRowIndex
; rowX
++) {
1985 CellDataArray
& row
= mRows
[rowX
];
1986 PRUint32 numCols
= row
.Length();
1988 for (colX
= aColIndex
+ totalColSpan
; colX
< numCols
; colX
++) {
1989 CellData
* data
= row
[colX
];
1991 // increase the origin and span counts beyond the spanned cols
1992 if (data
->IsOrig()) {
1993 // a cell that gets moved needs adjustment as well as it new orignating col
1994 data
->GetCellFrame()->SetColIndex(colX
);
1995 nsColInfo
* colInfo
= aMap
.GetColInfoAt(colX
);
1996 colInfo
->mNumCellsOrig
++;
1998 if (data
->IsColSpan()) {
1999 nsColInfo
* colInfo
= aMap
.GetColInfoAt(colX
);
2000 colInfo
->mNumCellsSpan
++;
2003 // decrease the origin and span counts within the spanned cols
2004 PRInt32 colX2
= colX
- totalColSpan
;
2005 nsColInfo
* colInfo2
= aMap
.GetColInfoAt(colX2
);
2006 if (data
->IsOrig()) {
2007 // the old originating col of a moved cell needs adjustment
2008 colInfo2
->mNumCellsOrig
--;
2010 if (data
->IsColSpan()) {
2011 colInfo2
->mNumCellsSpan
--;
2018 void nsCellMap::ShrinkWithoutRows(nsTableCellMap
& aMap
,
2019 PRInt32 aStartRowIndex
,
2020 PRInt32 aNumRowsToRemove
,
2021 nsRect
& aDamageArea
)
2023 NS_ASSERTION(!!aMap
.mBCInfo
== mIsBC
, "BC state mismatch");
2024 PRInt32 endRowIndex
= aStartRowIndex
+ aNumRowsToRemove
- 1;
2025 PRUint32 colCount
= aMap
.GetColCount();
2026 for (PRInt32 rowX
= endRowIndex
; rowX
>= aStartRowIndex
; --rowX
) {
2027 CellDataArray
& row
= mRows
[rowX
];
2029 for (colX
= 0; colX
< colCount
; colX
++) {
2030 CellData
* data
= row
.SafeElementAt(colX
);
2032 // Adjust the column counts.
2033 if (data
->IsOrig()) {
2034 // Decrement the column count.
2035 nsColInfo
* colInfo
= aMap
.GetColInfoAt(colX
);
2036 colInfo
->mNumCellsOrig
--;
2038 // colspan=0 is only counted as a spanned cell in the 1st col it spans
2039 else if (data
->IsColSpan()) {
2040 nsColInfo
* colInfo
= aMap
.GetColInfoAt(colX
);
2041 colInfo
->mNumCellsSpan
--;
2046 PRUint32 rowLength
= row
.Length();
2047 // Delete our row information.
2048 for (colX
= 0; colX
< rowLength
; colX
++) {
2049 DestroyCellData(row
[colX
]);
2052 mRows
.RemoveElementAt(rowX
);
2054 // Decrement our row and next available index counts.
2057 aMap
.RemoveColsAtEnd();
2059 SetDamageArea(0, aStartRowIndex
, aMap
.GetColCount(), 0, aDamageArea
);
2062 PRInt32
nsCellMap::GetColSpanForNewCell(nsTableCellFrame
& aCellFrameToAdd
,
2063 PRBool
& aIsZeroColSpan
) const
2065 aIsZeroColSpan
= PR_FALSE
;
2066 PRInt32 colSpan
= aCellFrameToAdd
.GetColSpan();
2068 colSpan
= 1; // set the min colspan it will be expanded later
2069 aIsZeroColSpan
= PR_TRUE
;
2074 PRInt32
nsCellMap::GetEffectiveColSpan(const nsTableCellMap
& aMap
,
2077 PRBool
& aZeroColSpan
) const
2079 PRInt32 numColsInTable
= aMap
.GetColCount();
2080 aZeroColSpan
= PR_FALSE
;
2081 PRInt32 colSpan
= 1;
2082 if (PRUint32(aRowIndex
) >= mRows
.Length()) {
2086 const CellDataArray
& row
= mRows
[aRowIndex
];
2089 PRInt32 maxCols
= numColsInTable
;
2090 PRBool hitOverlap
= PR_FALSE
; // XXX this is not ever being set to PR_TRUE
2091 for (colX
= aColIndex
+ 1; colX
< maxCols
; colX
++) {
2092 data
= row
.SafeElementAt(colX
);
2094 // for an overlapping situation get the colspan from the originating cell and
2095 // use that as the max number of cols to iterate. Since this is rare, only
2096 // pay the price of looking up the cell's colspan here.
2097 if (!hitOverlap
&& data
->IsOverlap()) {
2098 CellData
* origData
= row
.SafeElementAt(aColIndex
);
2099 if (origData
&& origData
->IsOrig()) {
2100 nsTableCellFrame
* cellFrame
= origData
->GetCellFrame();
2102 // possible change the number of colums to iterate
2103 maxCols
= PR_MIN(aColIndex
+ cellFrame
->GetColSpan(), maxCols
);
2104 if (colX
>= maxCols
)
2109 if (data
->IsColSpan()) {
2111 if (data
->IsZeroColSpan()) {
2112 aZeroColSpan
= PR_TRUE
;
2125 nsCellMap::GetRowSpanForNewCell(nsTableCellFrame
* aCellFrameToAdd
,
2127 PRBool
& aIsZeroRowSpan
) const
2129 aIsZeroRowSpan
= PR_FALSE
;
2130 PRInt32 rowSpan
= aCellFrameToAdd
->GetRowSpan();
2132 // Use a min value of 2 for a zero rowspan to make computations easier
2133 // elsewhere. Zero rowspans are only content dependent!
2134 rowSpan
= PR_MAX(2, mContentRowCount
- aRowIndex
);
2135 aIsZeroRowSpan
= PR_TRUE
;
2140 PRBool
nsCellMap::HasMoreThanOneCell(PRInt32 aRowIndex
) const
2142 const CellDataArray
& row
= mRows
.SafeElementAt(aRowIndex
, *sEmptyRow
);
2143 PRUint32 maxColIndex
= row
.Length();
2146 for (colIndex
= 0; colIndex
< maxColIndex
; colIndex
++) {
2147 CellData
* cellData
= row
[colIndex
];
2148 if (cellData
&& (cellData
->GetCellFrame() || cellData
->IsRowSpan()))
2157 nsCellMap::GetNumCellsOriginatingInRow(PRInt32 aRowIndex
) const
2159 const CellDataArray
& row
= mRows
.SafeElementAt(aRowIndex
, *sEmptyRow
);
2161 PRUint32 maxColIndex
= row
.Length();
2163 for (colIndex
= 0; colIndex
< maxColIndex
; colIndex
++) {
2164 CellData
* cellData
= row
[colIndex
];
2165 if (cellData
&& cellData
->IsOrig())
2171 PRInt32
nsCellMap::GetRowSpan(PRInt32 aRowIndex
,
2173 PRBool aGetEffective
) const
2175 PRInt32 rowSpan
= 1;
2176 PRInt32 rowCount
= (aGetEffective
) ? mContentRowCount
: mRows
.Length();
2178 for (rowX
= aRowIndex
+ 1; rowX
< rowCount
; rowX
++) {
2179 CellData
* data
= GetDataAt(rowX
, aColIndex
);
2181 if (data
->IsRowSpan()) {
2193 void nsCellMap::ShrinkWithoutCell(nsTableCellMap
& aMap
,
2194 nsTableCellFrame
& aCellFrame
,
2197 nsRect
& aDamageArea
)
2199 NS_ASSERTION(!!aMap
.mBCInfo
== mIsBC
, "BC state mismatch");
2200 PRUint32 colX
, rowX
;
2202 // get the rowspan and colspan from the cell map since the content may have changed
2204 PRUint32 numCols
= aMap
.GetColCount();
2205 PRInt32 rowSpan
= GetRowSpan(aRowIndex
, aColIndex
, PR_FALSE
);
2206 PRUint32 colSpan
= GetEffectiveColSpan(aMap
, aRowIndex
, aColIndex
, zeroColSpan
);
2207 PRUint32 endRowIndex
= aRowIndex
+ rowSpan
- 1;
2208 PRUint32 endColIndex
= aColIndex
+ colSpan
- 1;
2210 SetDamageArea(aColIndex
, aRowIndex
, 1 + endColIndex
- aColIndex
, 1 + endRowIndex
- aRowIndex
, aDamageArea
);
2212 if (aMap
.mTableFrame
.HasZeroColSpans()) {
2213 aMap
.mTableFrame
.SetNeedColSpanExpansion(PR_TRUE
);
2216 // adjust the col counts due to the deleted cell before removing it
2217 for (colX
= aColIndex
; colX
<= endColIndex
; colX
++) {
2218 nsColInfo
* colInfo
= aMap
.GetColInfoAt(colX
);
2219 if (colX
== PRUint32(aColIndex
)) {
2220 colInfo
->mNumCellsOrig
--;
2223 colInfo
->mNumCellsSpan
--;
2227 // remove the deleted cell and cellData entries for it
2228 for (rowX
= aRowIndex
; rowX
<= endRowIndex
; rowX
++) {
2229 CellDataArray
& row
= mRows
[rowX
];
2231 // endIndexForRow points at the first slot we don't want to clean up. This
2232 // makes the aColIndex == 0 case work right with our unsigned int colX.
2233 NS_ASSERTION(endColIndex
+ 1 <= row
.Length(), "span beyond the row size!");
2234 PRUint32 endIndexForRow
= PR_MIN(endColIndex
+ 1, row
.Length());
2236 // Since endIndexForRow <= row.Length(), enough to compare aColIndex to it.
2237 if (PRUint32(aColIndex
) < endIndexForRow
) {
2238 for (colX
= endIndexForRow
; colX
> PRUint32(aColIndex
); colX
--) {
2239 DestroyCellData(row
[colX
-1]);
2241 row
.RemoveElementsAt(aColIndex
, endIndexForRow
- aColIndex
);
2245 numCols
= aMap
.GetColCount();
2247 // update the row and col info due to shifting
2248 for (rowX
= aRowIndex
; rowX
<= endRowIndex
; rowX
++) {
2249 CellDataArray
& row
= mRows
[rowX
];
2250 for (colX
= aColIndex
; colX
< numCols
- colSpan
; colX
++) {
2251 CellData
* data
= row
.SafeElementAt(colX
);
2253 if (data
->IsOrig()) {
2254 // a cell that gets moved to the left needs adjustment in its new location
2255 data
->GetCellFrame()->SetColIndex(colX
);
2256 nsColInfo
* colInfo
= aMap
.GetColInfoAt(colX
);
2257 colInfo
->mNumCellsOrig
++;
2258 // a cell that gets moved to the left needs adjustment in its old location
2259 colInfo
= aMap
.GetColInfoAt(colX
+ colSpan
);
2261 colInfo
->mNumCellsOrig
--;
2265 else if (data
->IsColSpan()) {
2266 // a cell that gets moved to the left needs adjustment
2267 // in its new location
2268 nsColInfo
* colInfo
= aMap
.GetColInfoAt(colX
);
2269 colInfo
->mNumCellsSpan
++;
2270 // a cell that gets moved to the left needs adjustment
2271 // in its old location
2272 colInfo
= aMap
.GetColInfoAt(colX
+ colSpan
);
2274 colInfo
->mNumCellsSpan
--;
2280 aMap
.RemoveColsAtEnd();
2284 nsCellMap::RebuildConsideringRows(nsTableCellMap
& aMap
,
2285 PRInt32 aStartRowIndex
,
2286 nsVoidArray
* aRowsToInsert
,
2287 PRInt32 aNumRowsToRemove
,
2288 nsRect
& aDamageArea
)
2290 NS_ASSERTION(!!aMap
.mBCInfo
== mIsBC
, "BC state mismatch");
2291 // copy the old cell map into a new array
2292 PRUint32 numOrigRows
= mRows
.Length();
2293 nsTArray
<CellDataArray
> origRows
;
2294 mRows
.SwapElements(origRows
);
2296 PRInt32 rowNumberChange
;
2297 if (aRowsToInsert
) {
2298 rowNumberChange
= aRowsToInsert
->Count();
2300 rowNumberChange
= -aNumRowsToRemove
;
2303 // adjust mContentRowCount based on the function arguments as they are known to
2305 mContentRowCount
+= rowNumberChange
;
2306 NS_ASSERTION(mContentRowCount
>= 0, "previous mContentRowCount was wrong");
2307 // mRows is empty now. Grow it to the size we expect it to have.
2308 if (mContentRowCount
) {
2309 if (!Grow(aMap
, mContentRowCount
)) {
2310 // Bail, I guess... Not sure what else we can do here.
2315 // aStartRowIndex might be after all existing rows so we should limit the
2316 // copy to the amount of exisiting rows
2317 PRUint32 copyEndRowIndex
= PR_MIN(numOrigRows
, PRUint32(aStartRowIndex
));
2319 // rowX keeps track of where we are in mRows while setting up the
2323 // put back the rows before the affected ones just as before. Note that we
2324 // can't just copy the old rows in bit-for-bit, because they might be
2325 // spanning out into the rows we're adding/removing.
2326 for ( ; rowX
< copyEndRowIndex
; rowX
++) {
2327 const CellDataArray
& row
= origRows
[rowX
];
2328 PRUint32 numCols
= row
.Length();
2329 for (PRUint32 colX
= 0; colX
< numCols
; colX
++) {
2330 // put in the original cell from the cell map
2331 const CellData
* data
= row
.ElementAt(colX
);
2332 if (data
&& data
->IsOrig()) {
2333 AppendCell(aMap
, data
->GetCellFrame(), rowX
, PR_FALSE
, aDamageArea
);
2338 // Now handle the new rows being inserted, if any.
2339 PRUint32 copyStartRowIndex
;
2340 rowX
= aStartRowIndex
;
2341 if (aRowsToInsert
) {
2342 // add in the new cells and create rows if necessary
2343 PRInt32 numNewRows
= aRowsToInsert
->Count();
2344 for (PRInt32 newRowX
= 0; newRowX
< numNewRows
; newRowX
++) {
2345 nsTableRowFrame
* rFrame
= (nsTableRowFrame
*)aRowsToInsert
->ElementAt(newRowX
);
2346 nsIFrame
* cFrame
= rFrame
->GetFirstChild(nsnull
);
2348 if (IS_TABLE_CELL(cFrame
->GetType())) {
2349 AppendCell(aMap
, (nsTableCellFrame
*)cFrame
, rowX
, PR_FALSE
, aDamageArea
);
2351 cFrame
= cFrame
->GetNextSibling();
2355 copyStartRowIndex
= aStartRowIndex
;
2358 copyStartRowIndex
= aStartRowIndex
+ aNumRowsToRemove
;
2361 // put back the rows after the affected ones just as before. Again, we can't
2362 // just copy the old bits because that would not handle the new rows spanning
2363 // out or our earlier old rows spanning through the damaged area.
2364 for (PRUint32 copyRowX
= copyStartRowIndex
; copyRowX
< numOrigRows
;
2366 const CellDataArray
& row
= origRows
[copyRowX
];
2367 PRUint32 numCols
= row
.Length();
2368 for (PRUint32 colX
= 0; colX
< numCols
; colX
++) {
2369 // put in the original cell from the cell map
2370 CellData
* data
= row
.ElementAt(colX
);
2371 if (data
&& data
->IsOrig()) {
2372 AppendCell(aMap
, data
->GetCellFrame(), rowX
, PR_FALSE
, aDamageArea
);
2378 // delete the old cell map. Now rowX no longer has anything to do with mRows
2379 for (rowX
= 0; rowX
< numOrigRows
; rowX
++) {
2380 CellDataArray
& row
= origRows
[rowX
];
2381 PRUint32 len
= row
.Length();
2382 for (PRUint32 colX
= 0; colX
< len
; colX
++) {
2383 DestroyCellData(row
[colX
]);
2387 SetDamageArea(0, 0, aMap
.GetColCount(), GetRowCount(), aDamageArea
);
2390 void nsCellMap::RebuildConsideringCells(nsTableCellMap
& aMap
,
2391 PRInt32 aNumOrigCols
,
2392 nsVoidArray
* aCellFrames
,
2396 nsRect
& aDamageArea
)
2398 NS_ASSERTION(!!aMap
.mBCInfo
== mIsBC
, "BC state mismatch");
2399 // copy the old cell map into a new array
2400 PRUint32 numOrigRows
= mRows
.Length();
2401 nsTArray
<CellDataArray
> origRows
;
2402 mRows
.SwapElements(origRows
);
2404 PRInt32 numNewCells
= (aCellFrames
) ? aCellFrames
->Count() : 0;
2406 // the new cells might extend the previous column number
2407 NS_ASSERTION(aNumOrigCols
>= aColIndex
, "Appending cells far beyond cellmap data?!");
2408 PRInt32 numCols
= aInsert
? PR_MAX(aNumOrigCols
, aColIndex
+ 1) : aNumOrigCols
;
2410 // build the new cell map. Hard to say what, if anything, we can preallocate
2411 // here... Should come back to that sometime, perhaps.
2413 for (rowX
= 0; rowX
< numOrigRows
; rowX
++) {
2414 const CellDataArray
& row
= origRows
[rowX
];
2415 for (PRInt32 colX
= 0; colX
< numCols
; colX
++) {
2416 if ((rowX
== aRowIndex
) && (colX
== aColIndex
)) {
2417 if (aInsert
) { // put in the new cells
2418 for (PRInt32 cellX
= 0; cellX
< numNewCells
; cellX
++) {
2419 nsTableCellFrame
* cell
= (nsTableCellFrame
*)aCellFrames
->ElementAt(cellX
);
2421 AppendCell(aMap
, cell
, rowX
, PR_FALSE
, aDamageArea
);
2426 continue; // do not put the deleted cell back
2429 // put in the original cell from the cell map
2430 CellData
* data
= row
.SafeElementAt(colX
);
2431 if (data
&& data
->IsOrig()) {
2432 AppendCell(aMap
, data
->GetCellFrame(), rowX
, PR_FALSE
, aDamageArea
);
2436 if (aInsert
&& numOrigRows
<= aRowIndex
) { // append the new cells below the last original row
2437 NS_ASSERTION (numOrigRows
== aRowIndex
, "Appending cells far beyond the last row");
2438 for (PRInt32 cellX
= 0; cellX
< numNewCells
; cellX
++) {
2439 nsTableCellFrame
* cell
= (nsTableCellFrame
*)aCellFrames
->ElementAt(cellX
);
2441 AppendCell(aMap
, cell
, aRowIndex
, PR_FALSE
, aDamageArea
);
2446 // delete the old cell map
2447 for (rowX
= 0; rowX
< numOrigRows
; rowX
++) {
2448 CellDataArray
& row
= origRows
[rowX
];
2449 PRUint32 len
= row
.Length();
2450 for (PRUint32 colX
= 0; colX
< len
; colX
++) {
2451 DestroyCellData(row
.SafeElementAt(colX
));
2454 // expand the cellmap to cover empty content rows
2455 if (mRows
.Length() < mContentRowCount
) {
2456 Grow(aMap
, mContentRowCount
- mRows
.Length());
2461 void nsCellMap::RemoveCell(nsTableCellMap
& aMap
,
2462 nsTableCellFrame
* aCellFrame
,
2464 nsRect
& aDamageArea
)
2466 PRUint32 numRows
= mRows
.Length();
2467 if (PRUint32(aRowIndex
) >= numRows
) {
2468 NS_ERROR("bad arg in nsCellMap::RemoveCell");
2471 PRInt32 numCols
= aMap
.GetColCount();
2473 // Now aRowIndex is guaranteed OK.
2475 // get the starting col index of the cell to remove
2476 PRInt32 startColIndex
;
2477 for (startColIndex
= 0; startColIndex
< numCols
; startColIndex
++) {
2478 CellData
* data
= mRows
[aRowIndex
].SafeElementAt(startColIndex
);
2479 if (data
&& (data
->IsOrig()) && (aCellFrame
== data
->GetCellFrame())) {
2480 break; // we found the col index
2484 PRInt32 rowSpan
= GetRowSpan(aRowIndex
, startColIndex
, PR_FALSE
);
2485 // record whether removing the cells is going to cause complications due
2486 // to existing row spans, col spans or table sizing.
2487 PRBool spansCauseRebuild
= CellsSpanInOrOut(aRowIndex
,
2488 aRowIndex
+ rowSpan
- 1,
2489 startColIndex
, numCols
- 1);
2490 // XXX if the cell has a col span to the end of the map, and the end has no originating
2491 // cells, we need to assume that this the only such cell, and rebuild so that there are
2492 // no extraneous cols at the end. The same is true for removing rows.
2493 if (!aCellFrame
->GetRowSpan() || !aCellFrame
->GetColSpan())
2494 spansCauseRebuild
= PR_TRUE
;
2496 if (spansCauseRebuild
) {
2497 aMap
.RebuildConsideringCells(this, nsnull
, aRowIndex
, startColIndex
, PR_FALSE
, aDamageArea
);
2500 ShrinkWithoutCell(aMap
, *aCellFrame
, aRowIndex
, startColIndex
, aDamageArea
);
2504 void nsCellMap::ExpandZeroColSpans(nsTableCellMap
& aMap
)
2506 NS_ASSERTION(!!aMap
.mBCInfo
== mIsBC
, "BC state mismatch");
2507 PRUint32 numRows
= mRows
.Length();
2508 PRUint32 numCols
= aMap
.GetColCount();
2509 PRUint32 rowIndex
, colIndex
;
2511 for (rowIndex
= 0; rowIndex
< numRows
; rowIndex
++) {
2512 for (colIndex
= 0; colIndex
< numCols
; colIndex
++) {
2513 CellData
* data
= mRows
[rowIndex
].SafeElementAt(colIndex
);
2514 if (!data
|| !data
->IsOrig())
2516 nsTableCellFrame
* cell
= data
->GetCellFrame();
2517 NS_ASSERTION(cell
, "There has to be a cell");
2518 PRInt32 cellRowSpan
= cell
->GetRowSpan();
2519 PRInt32 cellColSpan
= cell
->GetColSpan();
2520 PRBool rowZeroSpan
= (0 == cell
->GetRowSpan());
2521 PRBool colZeroSpan
= (0 == cell
->GetColSpan());
2523 aMap
.mTableFrame
.SetHasZeroColSpans(PR_TRUE
);
2525 NS_ASSERTION(numRows
> 0, "Bogus numRows");
2526 NS_ASSERTION(numCols
> 0, "Bogus numCols");
2527 PRUint32 endRowIndex
= rowZeroSpan
? numRows
- 1 :
2528 rowIndex
+ cellRowSpan
- 1;
2529 PRUint32 endColIndex
= colZeroSpan
? numCols
- 1 :
2530 colIndex
+ cellColSpan
- 1;
2531 PRUint32 colX
, rowX
;
2532 colX
= colIndex
+ 1;
2533 while (colX
<= endColIndex
) {
2534 // look at columns from here to our colspan. For each one, check
2535 // the rows from here to our rowspan to make sure there is no
2536 // obstacle to marking that column as a zerospanned column; if there
2537 // isn't, mark it so
2538 for (rowX
= rowIndex
; rowX
<= endRowIndex
; rowX
++) {
2539 CellData
* oldData
= GetDataAt(rowX
, colX
);
2541 if (oldData
->IsOrig()) {
2542 break; // something is in the way
2544 if (oldData
->IsRowSpan()) {
2545 if ((rowX
- rowIndex
) != oldData
->GetRowSpanOffset()) {
2549 if (oldData
->IsColSpan()) {
2550 if ((colX
- colIndex
) != oldData
->GetColSpanOffset()) {
2556 if (endRowIndex
>= rowX
)
2557 break;// we hit something
2558 for (rowX
= rowIndex
; rowX
<= endRowIndex
; rowX
++) {
2559 CellData
* newData
= AllocCellData(nsnull
);
2560 if (!newData
) return;
2562 newData
->SetColSpanOffset(colX
- colIndex
);
2563 newData
->SetZeroColSpan(PR_TRUE
);
2565 if (rowX
> rowIndex
) {
2566 newData
->SetRowSpanOffset(rowX
- rowIndex
);
2568 newData
->SetZeroRowSpan(PR_TRUE
);
2570 SetDataAt(aMap
, *newData
, rowX
, colX
);
2573 } // while (colX <= endColIndex)
2579 void nsCellMap::Dump(PRBool aIsBorderCollapse
) const
2581 printf("\n ***** START GROUP CELL MAP DUMP ***** %p\n", (void*)this);
2582 nsTableRowGroupFrame
* rg
= GetRowGroup();
2583 const nsStyleDisplay
* display
= rg
->GetStyleDisplay();
2584 switch (display
->mDisplay
) {
2585 case NS_STYLE_DISPLAY_TABLE_HEADER_GROUP
:
2588 case NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP
:
2591 case NS_STYLE_DISPLAY_TABLE_ROW_GROUP
:
2595 printf("HUH? wrong display type on rowgroup");
2597 PRUint32 mapRowCount
= mRows
.Length();
2598 printf("mapRowCount=%u tableRowCount=%d\n", mapRowCount
, mContentRowCount
);
2601 PRUint32 rowIndex
, colIndex
;
2602 for (rowIndex
= 0; rowIndex
< mapRowCount
; rowIndex
++) {
2603 const CellDataArray
& row
= mRows
[rowIndex
];
2604 printf(" row %d : ", rowIndex
);
2605 PRUint32 colCount
= row
.Length();
2606 for (colIndex
= 0; colIndex
< colCount
; colIndex
++) {
2607 CellData
* cd
= row
[colIndex
];
2610 printf("C%d,%d ", rowIndex
, colIndex
);
2612 nsTableCellFrame
* cell
= nsnull
;
2613 if (cd
->IsRowSpan()) {
2614 cell
= GetCellFrame(rowIndex
, colIndex
, *cd
, PR_TRUE
);
2617 if (cd
->IsColSpan()) {
2618 cell
= GetCellFrame(rowIndex
, colIndex
, *cd
, PR_FALSE
);
2621 if (!(cd
->IsRowSpan() && cd
->IsColSpan())) {
2630 if (aIsBorderCollapse
) {
2632 BCBorderOwner owner
;
2636 for (PRInt32 i
= 0; i
<= 2; i
++) {
2638 for (colIndex
= 0; colIndex
< colCount
; colIndex
++) {
2639 BCCellData
* cd
= (BCCellData
*)row
[colIndex
];
2642 size
= cd
->mData
.GetTopEdge(owner
, segStart
);
2643 printf("t=%d%d%d ", size
, owner
, segStart
);
2646 size
= cd
->mData
.GetLeftEdge(owner
, segStart
);
2647 printf("l=%d%d%d ", size
, owner
, segStart
);
2650 size
= cd
->mData
.GetCorner(side
, bevel
);
2651 printf("c=%d%d%d ", size
, side
, bevel
);
2660 // output info mapping Ci,j to cell address
2661 PRUint32 cellCount
= 0;
2662 for (PRUint32 rIndex
= 0; rIndex
< mapRowCount
; rIndex
++) {
2663 const CellDataArray
& row
= mRows
[rIndex
];
2664 PRUint32 colCount
= row
.Length();
2666 for (colIndex
= 0; colIndex
< colCount
; colIndex
++) {
2667 CellData
* cd
= row
[colIndex
];
2670 nsTableCellFrame
* cellFrame
= cd
->GetCellFrame();
2671 PRInt32 cellFrameColIndex
;
2672 cellFrame
->GetColIndex(cellFrameColIndex
);
2673 printf("C%d,%d=%p(%d) ", rIndex
, colIndex
, (void*)cellFrame
,
2682 printf(" ***** END GROUP CELL MAP DUMP *****\n");
2687 nsCellMap::IsZeroColSpan(PRInt32 aRowIndex
,
2688 PRInt32 aColIndex
) const
2691 mRows
.SafeElementAt(aRowIndex
, *sEmptyRow
).SafeElementAt(aColIndex
);
2692 return data
&& data
->IsZeroColSpan();
2696 nsCellMap::GetDataAt(PRInt32 aMapRowIndex
,
2697 PRInt32 aColIndex
) const
2700 mRows
.SafeElementAt(aMapRowIndex
, *sEmptyRow
).SafeElementAt(aColIndex
);
2703 // only called if the cell at aMapRowIndex, aColIndex is null or dead
2704 // (the latter from ExpandZeroColSpans).
2705 void nsCellMap::SetDataAt(nsTableCellMap
& aMap
,
2707 PRInt32 aMapRowIndex
,
2710 NS_ASSERTION(!!aMap
.mBCInfo
== mIsBC
, "BC state mismatch");
2711 if (PRUint32(aMapRowIndex
) >= mRows
.Length()) {
2712 NS_ERROR("SetDataAt called with row index > num rows");
2716 CellDataArray
& row
= mRows
[aMapRowIndex
];
2718 // the table map may need cols added
2719 PRInt32 numColsToAdd
= aColIndex
+ 1 - aMap
.GetColCount();
2720 if (numColsToAdd
> 0) {
2721 aMap
.AddColsAtEnd(numColsToAdd
);
2723 // the row may need cols added
2724 numColsToAdd
= aColIndex
+ 1 - row
.Length();
2725 if (numColsToAdd
> 0) {
2726 // XXXbz need to handle allocation failures.
2727 GrowRow(row
, numColsToAdd
);
2730 DestroyCellData(row
[aColIndex
]);
2732 row
.ReplaceElementsAt(aColIndex
, 1, &aNewCell
);
2733 // update the originating cell counts if cell originates in this row, col
2734 nsColInfo
* colInfo
= aMap
.GetColInfoAt(aColIndex
);
2736 if (aNewCell
.IsOrig()) {
2737 colInfo
->mNumCellsOrig
++;
2739 else if (aNewCell
.IsColSpan()) {
2740 colInfo
->mNumCellsSpan
++;
2743 else NS_ERROR("SetDataAt called with col index > table map num cols");
2747 nsCellMap::GetCellInfoAt(const nsTableCellMap
& aMap
,
2750 PRBool
* aOriginates
,
2751 PRInt32
* aColSpan
) const
2754 *aOriginates
= PR_FALSE
;
2756 CellData
* data
= GetDataAt(aRowX
, aColX
);
2757 nsTableCellFrame
* cellFrame
= nsnull
;
2759 if (data
->IsOrig()) {
2760 cellFrame
= data
->GetCellFrame();
2762 *aOriginates
= PR_TRUE
;
2765 cellFrame
= GetCellFrame(aRowX
, aColX
, *data
, PR_TRUE
);
2767 if (cellFrame
&& aColSpan
) {
2768 PRInt32 initialColIndex
;
2769 cellFrame
->GetColIndex(initialColIndex
);
2771 *aColSpan
= GetEffectiveColSpan(aMap
, aRowX
, initialColIndex
, zeroSpan
);
2778 PRBool
nsCellMap::RowIsSpannedInto(PRInt32 aRowIndex
,
2779 PRInt32 aNumEffCols
) const
2781 if ((0 > aRowIndex
) || (aRowIndex
>= mContentRowCount
)) {
2784 for (PRInt32 colIndex
= 0; colIndex
< aNumEffCols
; colIndex
++) {
2785 CellData
* cd
= GetDataAt(aRowIndex
, colIndex
);
2786 if (cd
) { // there's really a cell at (aRowIndex, colIndex)
2787 if (cd
->IsSpan()) { // the cell at (aRowIndex, colIndex) is the result of a span
2788 if (cd
->IsRowSpan() && GetCellFrame(aRowIndex
, colIndex
, *cd
, PR_TRUE
)) { // XXX why the last check
2797 PRBool
nsCellMap::RowHasSpanningCells(PRInt32 aRowIndex
,
2798 PRInt32 aNumEffCols
) const
2800 if ((0 > aRowIndex
) || (aRowIndex
>= mContentRowCount
)) {
2803 if (aRowIndex
!= mContentRowCount
- 1) {
2804 // aRowIndex is not the last row, so we check the next row after aRowIndex for spanners
2805 for (PRInt32 colIndex
= 0; colIndex
< aNumEffCols
; colIndex
++) {
2806 CellData
* cd
= GetDataAt(aRowIndex
, colIndex
);
2807 if (cd
&& (cd
->IsOrig())) { // cell originates
2808 CellData
* cd2
= GetDataAt(aRowIndex
+ 1, colIndex
);
2809 if (cd2
&& cd2
->IsRowSpan()) { // cd2 is spanned by a row
2810 if (cd
->GetCellFrame() == GetCellFrame(aRowIndex
+ 1, colIndex
, *cd2
, PR_TRUE
)) {
2820 PRBool
nsCellMap::ColHasSpanningCells(PRInt32 aColIndex
) const
2822 for (PRInt32 rowIndex
= 0; rowIndex
< mContentRowCount
; rowIndex
++) {
2823 CellData
* cd
= GetDataAt(rowIndex
, aColIndex
);
2824 if (cd
&& (cd
->IsOrig())) { // cell originates
2825 CellData
* cd2
= GetDataAt(rowIndex
, aColIndex
+1);
2826 if (cd2
&& cd2
->IsColSpan()) { // cd2 is spanned by a col
2827 if (cd
->GetCellFrame() == GetCellFrame(rowIndex
, aColIndex
+ 1, *cd2
, PR_FALSE
)) {
2836 void nsCellMap::DestroyCellData(CellData
* aData
)
2843 BCCellData
* bcData
= static_cast<BCCellData
*>(aData
);
2844 bcData
->~BCCellData();
2845 mPresContext
->FreeToShell(sizeof(BCCellData
), bcData
);
2848 mPresContext
->FreeToShell(sizeof(CellData
), aData
);
2852 CellData
* nsCellMap::AllocCellData(nsTableCellFrame
* aOrigCell
)
2855 BCCellData
* data
= (BCCellData
*)
2856 mPresContext
->AllocateFromShell(sizeof(BCCellData
));
2858 new (data
) BCCellData(aOrigCell
);
2863 CellData
* data
= (CellData
*)
2864 mPresContext
->AllocateFromShell(sizeof(CellData
));
2866 new (data
) CellData(aOrigCell
);
2872 nsCellMapColumnIterator::AdvanceRowGroup()
2875 mCurMapStart
+= mCurMapContentRowCount
;
2876 mCurMap
= mCurMap
->GetNextSibling();
2878 // Set mCurMapContentRowCount and mCurMapRelevantRowCount to 0 in case
2879 // mCurMap has no next sibling. This can happen if we just handled the
2880 // last originating cell. Future calls will end up with mFoundCells ==
2881 // mOrigCells, but for this one mFoundCells was definitely not big enough
2883 mCurMapContentRowCount
= 0;
2884 mCurMapRelevantRowCount
= 0;
2888 mCurMapContentRowCount
= mCurMap
->GetRowCount();
2889 PRUint32 rowArrayLength
= mCurMap
->mRows
.Length();
2890 mCurMapRelevantRowCount
= PR_MIN(mCurMapContentRowCount
, rowArrayLength
);
2891 } while (0 == mCurMapRelevantRowCount
);
2893 NS_ASSERTION(mCurMapRelevantRowCount
!= 0 || !mCurMap
,
2894 "How did that happen?");
2896 // Set mCurMapRow to 0, since cells can't span across table row groups.
2901 nsCellMapColumnIterator::IncrementRow(PRInt32 aIncrement
)
2903 NS_PRECONDITION(aIncrement
>= 0, "Bogus increment");
2904 NS_PRECONDITION(mCurMap
, "Bogus mOrigCells?");
2905 if (aIncrement
== 0) {
2909 mCurMapRow
+= aIncrement
;
2910 if (mCurMapRow
>= mCurMapRelevantRowCount
) {
2917 nsCellMapColumnIterator::GetNextFrame(PRInt32
* aRow
, PRInt32
* aColSpan
)
2919 // Fast-path for the case when we don't have anything left in the column and
2921 if (mFoundCells
== mOrigCells
) {
2928 NS_ASSERTION(mCurMapRow
< mCurMapRelevantRowCount
, "Bogus mOrigCells?");
2929 // Safe to just get the row (which is faster than calling GetDataAt(), but
2930 // there may not be that many cells in it, so have to use SafeElementAt for
2932 const nsCellMap::CellDataArray
& row
= mCurMap
->mRows
[mCurMapRow
];
2933 CellData
* cellData
= row
.SafeElementAt(mCol
);
2934 if (!cellData
|| cellData
->IsDead()) {
2935 // Could hit this if there are fewer cells in this row than others, for
2941 if (cellData
->IsColSpan()) {
2942 // Look up the originating data for this cell, advance by its relative rowspan.
2943 PRInt32 rowspanOffset
= cellData
->GetRowSpanOffset();
2944 nsTableCellFrame
* cellFrame
= mCurMap
->GetCellFrame(mCurMapRow
, mCol
, *cellData
, PR_FALSE
);
2945 NS_ASSERTION(cellFrame
,"Must have usable originating data here");
2946 PRInt32 rowSpan
= cellFrame
->GetRowSpan();
2951 IncrementRow(rowSpan
- rowspanOffset
);
2956 NS_ASSERTION(cellData
->IsOrig(),
2957 "Must have originating cellData by this point. "
2958 "See comment on mCurMapRow in header.");
2960 nsTableCellFrame
* cellFrame
= cellData
->GetCellFrame();
2961 NS_ASSERTION(cellFrame
, "Orig data without cellframe?");
2963 *aRow
= mCurMapStart
+ mCurMapRow
;
2964 PRBool ignoredZeroSpan
;
2965 *aColSpan
= mCurMap
->GetEffectiveColSpan(*mMap
, mCurMapRow
, mCol
,
2968 IncrementRow(cellFrame
->GetRowSpan());
2972 NS_ASSERTION(cellData
= mMap
->GetDataAt(*aRow
, mCol
),
2973 "Giving caller bogus row?");
2978 NS_NOTREACHED("Can't get here");