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 ***** */
37 #include "nsTableRowFrame.h"
38 #include "nsTableRowGroupFrame.h"
39 #include "nsIRenderingContext.h"
40 #include "nsIPresShell.h"
41 #include "nsPresContext.h"
42 #include "nsStyleContext.h"
43 #include "nsStyleConsts.h"
44 #include "nsGkAtoms.h"
45 #include "nsIContent.h"
46 #include "nsTableFrame.h"
47 #include "nsTableCellFrame.h"
48 #include "nsCSSRendering.h"
49 #include "nsHTMLParts.h"
50 #include "nsTableColGroupFrame.h"
51 #include "nsTableColFrame.h"
53 #include "nsDisplayList.h"
55 struct nsTableCellReflowState
: public nsHTMLReflowState
57 nsTableCellReflowState(nsPresContext
* aPresContext
,
58 const nsHTMLReflowState
& aParentReflowState
,
60 const nsSize
& aAvailableSpace
,
61 PRBool aInit
= PR_TRUE
)
62 : nsHTMLReflowState(aPresContext
, aParentReflowState
, aFrame
,
63 aAvailableSpace
, -1, -1, aInit
)
67 void FixUp(const nsSize
& aAvailSpace
);
70 void nsTableCellReflowState::FixUp(const nsSize
& aAvailSpace
)
72 // fix the mComputed values during a pass 2 reflow since the cell can be a percentage base
73 NS_ASSERTION(NS_UNCONSTRAINEDSIZE
!= aAvailSpace
.width
,
74 "unconstrained available width in reflow");
75 if (NS_UNCONSTRAINEDSIZE
!= ComputedWidth()) {
76 nscoord computedWidth
=
77 aAvailSpace
.width
- mComputedBorderPadding
.LeftRight();
78 computedWidth
= PR_MAX(0, computedWidth
);
79 SetComputedWidth(computedWidth
);
81 if (NS_UNCONSTRAINEDSIZE
!= ComputedHeight() &&
82 NS_UNCONSTRAINEDSIZE
!= aAvailSpace
.height
) {
83 nscoord computedHeight
=
84 aAvailSpace
.height
- mComputedBorderPadding
.TopBottom();
85 computedHeight
= PR_MAX(0, computedHeight
);
86 SetComputedHeight(computedHeight
);
91 nsTableRowFrame::InitChildReflowState(nsPresContext
& aPresContext
,
92 const nsSize
& aAvailSize
,
93 PRBool aBorderCollapse
,
94 nsTableCellReflowState
& aReflowState
)
96 nsMargin collapseBorder
;
97 nsMargin
* pCollapseBorder
= nsnull
;
98 if (aBorderCollapse
) {
99 // we only reflow cells, so don't need to check frame type
100 nsBCTableCellFrame
* bcCellFrame
= (nsBCTableCellFrame
*)aReflowState
.frame
;
102 pCollapseBorder
= bcCellFrame
->GetBorderWidth(collapseBorder
);
105 aReflowState
.Init(&aPresContext
, -1, -1, pCollapseBorder
);
106 aReflowState
.FixUp(aAvailSize
);
110 nsTableRowFrame::SetFixedHeight(nscoord aValue
)
112 nscoord height
= PR_MAX(0, aValue
);
113 if (HasFixedHeight()) {
114 if (height
> mStyleFixedHeight
) {
115 mStyleFixedHeight
= height
;
119 mStyleFixedHeight
= height
;
121 SetHasFixedHeight(PR_TRUE
);
127 nsTableRowFrame::SetPctHeight(float aPctValue
,
130 nscoord height
= PR_MAX(0, NSToCoordRound(aPctValue
* 100.0f
));
131 if (HasPctHeight()) {
132 if ((height
> mStylePctHeight
) || aForce
) {
133 mStylePctHeight
= height
;
137 mStylePctHeight
= height
;
139 SetHasPctHeight(PR_TRUE
);
144 /* ----------- nsTableRowFrame ---------- */
146 nsTableRowFrame::nsTableRowFrame(nsStyleContext
* aContext
)
147 : nsHTMLContainerFrame(aContext
)
149 mBits
.mRowIndex
= mBits
.mFirstInserted
= 0;
153 nsTableRowFrame::~nsTableRowFrame()
158 nsTableRowFrame::Init(nsIContent
* aContent
,
160 nsIFrame
* aPrevInFlow
)
164 // Let the base class do its initialization
165 rv
= nsHTMLContainerFrame::Init(aContent
, aParent
, aPrevInFlow
);
167 NS_ASSERTION(NS_STYLE_DISPLAY_TABLE_ROW
== GetStyleDisplay()->mDisplay
,
168 "wrong display on table row frame");
172 nsTableRowFrame
* rowFrame
= (nsTableRowFrame
*)aPrevInFlow
;
174 SetRowIndex(rowFrame
->GetRowIndex());
181 nsTableRowFrame::DidSetStyleContext(nsStyleContext
* aOldStyleContext
)
183 if (!aOldStyleContext
) //avoid this on init
186 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
188 if (tableFrame
->IsBorderCollapse() &&
189 tableFrame
->BCRecalcNeeded(aOldStyleContext
, GetStyleContext())) {
190 nsRect
damageArea(0, GetRowIndex(), tableFrame
->GetColCount(), 1);
191 tableFrame
->SetBCDamageArea(damageArea
);
197 nsTableRowFrame::AppendFrames(nsIAtom
* aListName
,
198 nsIFrame
* aFrameList
)
200 NS_ASSERTION(!aListName
, "unexpected child list");
203 mFrames
.AppendFrames(nsnull
, aFrameList
);
205 // Add the new cell frames to the table
206 nsTableFrame
*tableFrame
= nsTableFrame::GetTableFrame(this);
207 for (nsIFrame
* childFrame
= aFrameList
; childFrame
;
208 childFrame
= childFrame
->GetNextSibling()) {
209 if (IS_TABLE_CELL(childFrame
->GetType())) {
210 // Add the cell to the cell map
211 tableFrame
->AppendCell((nsTableCellFrame
&)*childFrame
, GetRowIndex());
215 PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange
,
216 NS_FRAME_HAS_DIRTY_CHILDREN
);
217 tableFrame
->SetGeometryDirty();
224 nsTableRowFrame::InsertFrames(nsIAtom
* aListName
,
225 nsIFrame
* aPrevFrame
,
226 nsIFrame
* aFrameList
)
228 NS_ASSERTION(!aListName
, "unexpected child list");
229 NS_ASSERTION(!aPrevFrame
|| aPrevFrame
->GetParent() == this,
230 "inserting after sibling frame with different parent");
232 // Get the table frame
233 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
235 // gather the new frames (only those which are cells) into an array
236 nsIAtom
* cellFrameType
= (tableFrame
->IsBorderCollapse()) ? nsGkAtoms::bcTableCellFrame
: nsGkAtoms::tableCellFrame
;
237 nsTableCellFrame
* prevCellFrame
= (nsTableCellFrame
*)nsTableFrame::GetFrameAtOrBefore(this, aPrevFrame
, cellFrameType
);
238 nsVoidArray cellChildren
;
239 for (nsIFrame
* childFrame
= aFrameList
; childFrame
;
240 childFrame
= childFrame
->GetNextSibling()) {
241 if (IS_TABLE_CELL(childFrame
->GetType())) {
242 cellChildren
.AppendElement(childFrame
);
245 // insert the cells into the cell map
246 PRInt32 colIndex
= -1;
248 prevCellFrame
->GetColIndex(colIndex
);
250 tableFrame
->InsertCells(cellChildren
, GetRowIndex(), colIndex
);
252 // Insert the frames in the frame list
253 mFrames
.InsertFrames(nsnull
, aPrevFrame
, aFrameList
);
255 PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange
,
256 NS_FRAME_HAS_DIRTY_CHILDREN
);
257 tableFrame
->SetGeometryDirty();
263 nsTableRowFrame::RemoveFrame(nsIAtom
* aListName
,
266 NS_ASSERTION(!aListName
, "unexpected child list");
268 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
270 if (IS_TABLE_CELL(aOldFrame
->GetType())) {
271 nsTableCellFrame
* cellFrame
= (nsTableCellFrame
*)aOldFrame
;
273 cellFrame
->GetColIndex(colIndex
);
274 // remove the cell from the cell map
275 tableFrame
->RemoveCell(cellFrame
, GetRowIndex());
277 // Remove the frame and destroy it
278 mFrames
.DestroyFrame(aOldFrame
);
280 PresContext()->PresShell()->
281 FrameNeedsReflow(this, nsIPresShell::eTreeChange
,
282 NS_FRAME_HAS_DIRTY_CHILDREN
);
283 tableFrame
->SetGeometryDirty();
286 NS_ERROR("unexpected frame type");
287 return NS_ERROR_INVALID_ARG
;
294 /* virtual */ nsMargin
295 nsTableRowFrame::GetUsedMargin() const
297 return nsMargin(0,0,0,0);
300 /* virtual */ nsMargin
301 nsTableRowFrame::GetUsedBorder() const
303 return nsMargin(0,0,0,0);
306 /* virtual */ nsMargin
307 nsTableRowFrame::GetUsedPadding() const
309 return nsMargin(0,0,0,0);
313 GetHeightOfRowsSpannedBelowFirst(nsTableCellFrame
& aTableCellFrame
,
314 nsTableFrame
& aTableFrame
)
317 nscoord cellSpacingY
= aTableFrame
.GetCellSpacingY();
318 PRInt32 rowSpan
= aTableFrame
.GetEffectiveRowSpan(aTableCellFrame
);
319 // add in height of rows spanned beyond the 1st one
320 nsIFrame
* nextRow
= aTableCellFrame
.GetParent()->GetNextSibling();
321 for (PRInt32 rowX
= 1; ((rowX
< rowSpan
) && nextRow
);) {
322 if (nsGkAtoms::tableRowFrame
== nextRow
->GetType()) {
323 height
+= nextRow
->GetSize().height
;
326 height
+= cellSpacingY
;
327 nextRow
= nextRow
->GetNextSibling();
333 nsTableRowFrame::GetFirstCell()
335 nsIFrame
* childFrame
= mFrames
.FirstChild();
337 if (IS_TABLE_CELL(childFrame
->GetType())) {
338 return (nsTableCellFrame
*)childFrame
;
340 childFrame
= childFrame
->GetNextSibling();
346 * Post-reflow hook. This is where the table row does its post-processing
349 nsTableRowFrame::DidResize()
351 // Resize and re-align the cell frames based on our row height
352 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
356 nsTableIterator
iter(*this);
357 nsIFrame
* childFrame
= iter
.First();
359 nsHTMLReflowMetrics desiredSize
;
360 desiredSize
.width
= mRect
.width
;
361 desiredSize
.height
= mRect
.height
;
362 desiredSize
.mOverflowArea
= nsRect(0, 0, desiredSize
.width
,
366 if (IS_TABLE_CELL(childFrame
->GetType())) {
367 nsTableCellFrame
* cellFrame
= (nsTableCellFrame
*)childFrame
;
368 nscoord cellHeight
= mRect
.height
+ GetHeightOfRowsSpannedBelowFirst(*cellFrame
, *tableFrame
);
370 // resize the cell's height
371 nsRect cellRect
= cellFrame
->GetRect();
372 nsRect cellOverflowRect
= cellFrame
->GetOverflowRect();
373 if (cellRect
.height
!= cellHeight
)
375 cellFrame
->SetSize(nsSize(cellRect
.width
, cellHeight
));
376 nsTableFrame::InvalidateFrame(cellFrame
, cellRect
, cellOverflowRect
,
380 // realign cell content based on the new height. We might be able to
381 // skip this if the height didn't change... maybe. Hard to tell.
382 cellFrame
->VerticallyAlignChild(mMaxCellAscent
);
384 // Always store the overflow, even if the height didn't change, since
385 // we'll lose part of our overflow area otherwise.
386 ConsiderChildOverflow(desiredSize
.mOverflowArea
, cellFrame
);
388 // Note that if the cell's *content* needs to change in response
389 // to this height, it will get a special height reflow.
391 // Get the next child
392 childFrame
= iter
.Next();
394 FinishAndStoreOverflow(&desiredSize
);
396 nsContainerFrame::SyncFrameViewAfterReflow(PresContext(), this, GetView(), &desiredSize
.mOverflowArea
, 0);
398 // Let our base class do the usual work
401 // returns max-ascent amongst all cells that have 'vertical-align: baseline'
402 // *including* cells with rowspans
403 nscoord
nsTableRowFrame::GetMaxCellAscent() const
405 return mMaxCellAscent
;
408 nscoord
nsTableRowFrame::GetRowBaseline()
411 return mMaxCellAscent
;
413 // If we don't have a baseline on any of the cells we go for the lowest
414 // content edge of the inner block frames.
415 // Every table cell has a cell frame with its border and padding. Inside
416 // the cell is a block frame. The cell is as high as the tallest cell in
417 // the parent row. As a consequence the block frame might not touch both
418 // the top and the bottom padding of it parent cell frame at the same time.
420 // bbbbbbbbbbbbbbbbbb cell border: b
421 // bppppppppppppppppb cell padding: p
422 // bpxxxxxxxxxxxxxxpb inner block: x
426 // bpxxxxxxxxxxxxxxpb base line
429 // bppppppppppppppppb
430 // bbbbbbbbbbbbbbbbbb
432 nsTableIterator
iter(*this);
433 nsIFrame
* childFrame
= iter
.First();
436 if (IS_TABLE_CELL(childFrame
->GetType())) {
437 nsIFrame
* firstKid
= childFrame
->GetFirstChild(nsnull
);
438 ascent
= PR_MAX(ascent
, firstKid
->GetRect().YMost());
440 // Get the next child
441 childFrame
= iter
.Next();
446 nsTableRowFrame::GetHeight(nscoord aPctBasis
) const
449 if ((aPctBasis
> 0) && HasPctHeight()) {
450 height
= NSToCoordRound(GetPctHeight() * (float)aPctBasis
);
452 if (HasFixedHeight()) {
453 height
= PR_MAX(height
, GetFixedHeight());
455 return PR_MAX(height
, GetContentHeight());
459 nsTableRowFrame::ResetHeight(nscoord aFixedHeight
)
461 SetHasFixedHeight(PR_FALSE
);
462 SetHasPctHeight(PR_FALSE
);
467 if (aFixedHeight
> 0) {
468 SetFixedHeight(aFixedHeight
);
476 nsTableRowFrame::UpdateHeight(nscoord aHeight
,
479 nsTableFrame
* aTableFrame
,
480 nsTableCellFrame
* aCellFrame
)
482 if (!aTableFrame
|| !aCellFrame
) {
483 NS_ASSERTION(PR_FALSE
, "invalid call");
487 if (aHeight
!= NS_UNCONSTRAINEDSIZE
) {
488 if (!(aCellFrame
->HasVerticalAlignBaseline())) { // only the cell's height matters
489 if (GetHeight() < aHeight
) {
490 PRInt32 rowSpan
= aTableFrame
->GetEffectiveRowSpan(*aCellFrame
);
492 SetContentHeight(aHeight
);
496 else { // the alignment on the baseline can change the height
497 NS_ASSERTION((aAscent
!= NS_UNCONSTRAINEDSIZE
) && (aDescent
!= NS_UNCONSTRAINEDSIZE
), "invalid call");
498 // see if this is a long ascender
499 if (mMaxCellAscent
< aAscent
) {
500 mMaxCellAscent
= aAscent
;
502 // see if this is a long descender and without rowspan
503 if (mMaxCellDescent
< aDescent
) {
504 PRInt32 rowSpan
= aTableFrame
->GetEffectiveRowSpan(*aCellFrame
);
506 mMaxCellDescent
= aDescent
;
509 // keep the tallest height in sync
510 if (GetHeight() < mMaxCellAscent
+ mMaxCellDescent
) {
511 SetContentHeight(mMaxCellAscent
+ mMaxCellDescent
);
518 nsTableRowFrame::CalcHeight(const nsHTMLReflowState
& aReflowState
)
520 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
524 nscoord computedHeight
= (NS_UNCONSTRAINEDSIZE
== aReflowState
.ComputedHeight())
525 ? 0 : aReflowState
.ComputedHeight();
526 ResetHeight(computedHeight
);
528 const nsStylePosition
* position
= GetStylePosition();
529 if (eStyleUnit_Coord
== position
->mHeight
.GetUnit()) {
530 SetFixedHeight(position
->mHeight
.GetCoordValue());
532 else if (eStyleUnit_Percent
== position
->mHeight
.GetUnit()) {
533 SetPctHeight(position
->mHeight
.GetPercentValue());
536 for (nsIFrame
* kidFrame
= mFrames
.FirstChild(); kidFrame
;
537 kidFrame
= kidFrame
->GetNextSibling()) {
538 if (IS_TABLE_CELL(kidFrame
->GetType())) {
539 nscoord availWidth
= ((nsTableCellFrame
*)kidFrame
)->GetPriorAvailWidth();
540 nsSize desSize
= ((nsTableCellFrame
*)kidFrame
)->GetDesiredSize();
541 if ((NS_UNCONSTRAINEDSIZE
== aReflowState
.availableHeight
) && !GetPrevInFlow()) {
542 CalculateCellActualSize(kidFrame
, desSize
.width
, desSize
.height
, availWidth
);
544 // height may have changed, adjust descent to absorb any excess difference
546 if (!kidFrame
->GetFirstChild(nsnull
)->GetFirstChild(nsnull
))
547 ascent
= desSize
.height
;
549 ascent
= ((nsTableCellFrame
*)kidFrame
)->GetCellBaseline();
550 nscoord descent
= desSize
.height
- ascent
;
551 UpdateHeight(desSize
.height
, ascent
, descent
, tableFrame
, (nsTableCellFrame
*)kidFrame
);
558 * We need a custom display item for table row backgrounds. This is only used
559 * when the table row is the root of a stacking context (e.g., has 'opacity').
560 * Table row backgrounds can extend beyond the row frame bounds, when
561 * the row contains row-spanning cells.
563 class nsDisplayTableRowBackground
: public nsDisplayTableItem
{
565 nsDisplayTableRowBackground(nsTableRowFrame
* aFrame
) : nsDisplayTableItem(aFrame
) {
566 MOZ_COUNT_CTOR(nsDisplayTableRowBackground
);
568 #ifdef NS_BUILD_REFCNT_LOGGING
569 virtual ~nsDisplayTableRowBackground() {
570 MOZ_COUNT_DTOR(nsDisplayTableRowBackground
);
574 virtual void Paint(nsDisplayListBuilder
* aBuilder
, nsIRenderingContext
* aCtx
,
575 const nsRect
& aDirtyRect
);
576 NS_DISPLAY_DECL_NAME("TableRowBackground")
580 nsDisplayTableRowBackground::Paint(nsDisplayListBuilder
* aBuilder
,
581 nsIRenderingContext
* aCtx
, const nsRect
& aDirtyRect
) {
582 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(mFrame
);
584 nsPoint pt
= aBuilder
->ToReferenceFrame(mFrame
);
585 TableBackgroundPainter
painter(tableFrame
,
586 TableBackgroundPainter::eOrigin_TableRow
,
587 mFrame
->PresContext(), *aCtx
,
589 painter
.PaintRow(static_cast<nsTableRowFrame
*>(mFrame
));
593 nsTableRowFrame::BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
594 const nsRect
& aDirtyRect
,
595 const nsDisplayListSet
& aLists
)
597 if (!IsVisibleInSelection(aBuilder
))
600 PRBool isRoot
= aBuilder
->IsAtRootOfPseudoStackingContext();
601 nsDisplayTableItem
* item
= nsnull
;
603 // This background is created regardless of whether this frame is
604 // visible or not. Visibility decisions are delegated to the
605 // table background painter.
606 // We would use nsDisplayGeneric for this rare case except that we
607 // need the background to be larger than the row frame in some
609 item
= new (aBuilder
) nsDisplayTableRowBackground(this);
610 nsresult rv
= aLists
.BorderBackground()->AppendNewToTop(item
);
611 NS_ENSURE_SUCCESS(rv
, rv
);
614 return nsTableFrame::DisplayGenericTablePart(aBuilder
, this, aDirtyRect
, aLists
, item
);
618 nsTableRowFrame::GetSkipSides() const
621 if (nsnull
!= GetPrevInFlow()) {
622 skip
|= 1 << NS_SIDE_TOP
;
624 if (nsnull
!= GetNextInFlow()) {
625 skip
|= 1 << NS_SIDE_BOTTOM
;
630 // Calculate the cell's actual size given its pass2 desired width and height.
631 // Takes into account the specified height (in the style), and any special logic
632 // needed for backwards compatibility.
633 // Modifies the desired width and height that are passed in.
635 nsTableRowFrame::CalculateCellActualSize(nsIFrame
* aCellFrame
,
636 nscoord
& aDesiredWidth
,
637 nscoord
& aDesiredHeight
,
640 nscoord specifiedHeight
= 0;
642 // Get the height specified in the style information
643 const nsStylePosition
* position
= aCellFrame
->GetStylePosition();
645 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
647 return NS_ERROR_NULL_POINTER
;
649 PRInt32 rowSpan
= tableFrame
->GetEffectiveRowSpan((nsTableCellFrame
&)*aCellFrame
);
651 switch (position
->mHeight
.GetUnit()) {
652 case eStyleUnit_Coord
:
653 specifiedHeight
= position
->mHeight
.GetCoordValue();
655 SetFixedHeight(specifiedHeight
);
657 case eStyleUnit_Percent
: {
659 SetPctHeight(position
->mHeight
.GetPercentValue());
660 // pct heights are handled when all of the cells are finished, so don't set specifiedHeight
663 case eStyleUnit_Auto
:
668 // If the specified height is greater than the desired height, then use the specified height
669 if (specifiedHeight
> aDesiredHeight
)
670 aDesiredHeight
= specifiedHeight
;
672 if ((0 == aDesiredWidth
) && (NS_UNCONSTRAINEDSIZE
!= aAvailWidth
)) { // special Nav4 compatibility code for the width
673 aDesiredWidth
= aAvailWidth
;
679 // Calculates the available width for the table cell based on the known
680 // column widths taking into account column spans and column spacing
682 CalcAvailWidth(nsTableFrame
& aTableFrame
,
683 nsTableCellFrame
& aCellFrame
,
684 nscoord aCellSpacingX
,
685 nscoord
& aColAvailWidth
,
686 nscoord
& aCellAvailWidth
)
688 aColAvailWidth
= aCellAvailWidth
= NS_UNCONSTRAINEDSIZE
;
690 aCellFrame
.GetColIndex(colIndex
);
691 PRInt32 colspan
= aTableFrame
.GetEffectiveColSpan(aCellFrame
);
692 nscoord cellSpacing
= 0;
694 for (PRInt32 spanX
= 0; spanX
< colspan
; spanX
++) {
695 nscoord colWidth
= aTableFrame
.GetColumnWidth(colIndex
+ spanX
);
696 if (NS_UNCONSTRAINEDSIZE
== aColAvailWidth
) {
697 aColAvailWidth
= colWidth
;
700 aColAvailWidth
+= colWidth
;
702 if ((spanX
> 0) && aTableFrame
.ColumnHasCellSpacingBefore(colIndex
+ spanX
)) {
703 cellSpacing
+= aCellSpacingX
;
706 if (NS_UNCONSTRAINEDSIZE
!= aColAvailWidth
) {
707 aColAvailWidth
+= cellSpacing
;
709 aCellAvailWidth
= aColAvailWidth
;
713 GetSpaceBetween(PRInt32 aPrevColIndex
,
716 nsTableFrame
& aTableFrame
,
717 nscoord aCellSpacingX
,
718 PRBool aIsLeftToRight
,
719 PRBool aCheckVisibility
)
723 if (aIsLeftToRight
) {
724 for (colX
= aPrevColIndex
+ 1; aColIndex
> colX
; colX
++) {
725 PRBool isCollapsed
= PR_FALSE
;
726 if (!aCheckVisibility
) {
727 space
+= aTableFrame
.GetColumnWidth(colX
);
730 nsTableColFrame
* colFrame
= aTableFrame
.GetColFrame(colX
);
731 const nsStyleVisibility
* colVis
= colFrame
->GetStyleVisibility();
732 PRBool collapseCol
= (NS_STYLE_VISIBILITY_COLLAPSE
== colVis
->mVisible
);
733 nsIFrame
* cgFrame
= colFrame
->GetParent();
734 const nsStyleVisibility
* groupVis
= cgFrame
->GetStyleVisibility();
735 PRBool collapseGroup
= (NS_STYLE_VISIBILITY_COLLAPSE
==
737 isCollapsed
= collapseCol
|| collapseGroup
;
739 space
+= aTableFrame
.GetColumnWidth(colX
);
741 if (!isCollapsed
&& aTableFrame
.ColumnHasCellSpacingBefore(colX
)) {
742 space
+= aCellSpacingX
;
747 PRInt32 lastCol
= aColIndex
+ aColSpan
- 1;
748 for (colX
= aPrevColIndex
- 1; colX
> lastCol
; colX
--) {
749 PRBool isCollapsed
= PR_FALSE
;
750 if (!aCheckVisibility
) {
751 space
+= aTableFrame
.GetColumnWidth(colX
);
754 nsTableColFrame
* colFrame
= aTableFrame
.GetColFrame(colX
);
755 const nsStyleVisibility
* colVis
= colFrame
->GetStyleVisibility();
756 PRBool collapseCol
= (NS_STYLE_VISIBILITY_COLLAPSE
== colVis
->mVisible
);
757 nsIFrame
* cgFrame
= colFrame
->GetParent();
758 const nsStyleVisibility
* groupVis
= cgFrame
->GetStyleVisibility();
759 PRBool collapseGroup
= (NS_STYLE_VISIBILITY_COLLAPSE
==
761 isCollapsed
= collapseCol
|| collapseGroup
;
763 space
+= aTableFrame
.GetColumnWidth(colX
);
765 if (!isCollapsed
&& aTableFrame
.ColumnHasCellSpacingBefore(colX
)) {
766 space
+= aCellSpacingX
;
773 // subtract the heights of aRow's prev in flows from the unpaginated height
775 nscoord
CalcHeightFromUnpaginatedHeight(nsPresContext
* aPresContext
,
776 nsTableRowFrame
& aRow
)
779 nsTableRowFrame
* firstInFlow
= (nsTableRowFrame
*)aRow
.GetFirstInFlow();
780 if (!firstInFlow
) ABORT1(0);
781 if (firstInFlow
->HasUnpaginatedHeight()) {
782 height
= firstInFlow
->GetUnpaginatedHeight(aPresContext
);
783 for (nsIFrame
* prevInFlow
= aRow
.GetPrevInFlow(); prevInFlow
;
784 prevInFlow
= prevInFlow
->GetPrevInFlow()) {
785 height
-= prevInFlow
->GetSize().height
;
788 return PR_MAX(height
, 0);
792 nsTableRowFrame::ReflowChildren(nsPresContext
* aPresContext
,
793 nsHTMLReflowMetrics
& aDesiredSize
,
794 const nsHTMLReflowState
& aReflowState
,
795 nsTableFrame
& aTableFrame
,
796 nsReflowStatus
& aStatus
)
798 aStatus
= NS_FRAME_COMPLETE
;
800 PRBool borderCollapse
= (((nsTableFrame
*)aTableFrame
.GetFirstInFlow())->IsBorderCollapse());
802 // XXXldb Should we be checking constrained height instead?
803 PRBool isPaginated
= aPresContext
->IsPaginated();
807 nscoord cellSpacingX
= aTableFrame
.GetCellSpacingX();
808 PRInt32 cellColSpan
= 1; // must be defined here so it's set properly for non-cell kids
810 nsTableIterator
iter(*this);
811 // remember the col index of the previous cell to handle rowspans into this row
812 PRInt32 firstPrevColIndex
= (iter
.IsLeftToRight()) ? -1 : aTableFrame
.GetColCount();
813 PRInt32 prevColIndex
= firstPrevColIndex
;
814 nscoord x
= 0; // running total of children x offset
816 // This computes the max of all cell heights
817 nscoord cellMaxHeight
= 0;
819 // Reflow each of our existing cell frames
820 for (nsIFrame
* kidFrame
= iter
.First(); kidFrame
; kidFrame
= iter
.Next()) {
821 nsIAtom
* frameType
= kidFrame
->GetType();
822 if (!IS_TABLE_CELL(frameType
)) {
823 // XXXldb nsCSSFrameConstructor needs to enforce this!
824 NS_NOTREACHED("yikes, a non-row child");
826 // it's an unknown frame type, give it a generic reflow and ignore the results
827 nsTableCellReflowState
kidReflowState(aPresContext
, aReflowState
,
828 kidFrame
, nsSize(0,0), PR_FALSE
);
829 InitChildReflowState(*aPresContext
, nsSize(0,0), PR_FALSE
, kidReflowState
);
830 nsHTMLReflowMetrics desiredSize
;
831 nsReflowStatus status
;
832 ReflowChild(kidFrame
, aPresContext
, desiredSize
, kidReflowState
, 0, 0, 0, status
);
833 kidFrame
->DidReflow(aPresContext
, nsnull
, NS_FRAME_REFLOW_FINISHED
);
838 nsTableCellFrame
* cellFrame
= static_cast<nsTableCellFrame
*>(kidFrame
);
840 // See if we should only reflow the dirty child frames
841 PRBool doReflowChild
= PR_TRUE
;
842 if (!aReflowState
.ShouldReflowAllKids() &&
843 !aTableFrame
.IsGeometryDirty() &&
844 !NS_SUBTREE_DIRTY(kidFrame
)) {
845 if (!aReflowState
.mFlags
.mSpecialHeightReflow
)
846 doReflowChild
= PR_FALSE
;
848 else if ((NS_UNCONSTRAINEDSIZE
!= aReflowState
.availableHeight
)) {
849 // We don't reflow a rowspan >1 cell here with a constrained height.
850 // That happens in nsTableRowGroupFrame::SplitSpanningCells.
851 if (aTableFrame
.GetEffectiveRowSpan(*cellFrame
) > 1) {
852 doReflowChild
= PR_FALSE
;
855 if (aReflowState
.mFlags
.mSpecialHeightReflow
) {
856 if (!isPaginated
&& !(cellFrame
->GetStateBits() &
857 NS_FRAME_CONTAINS_RELATIVE_HEIGHT
)) {
862 PRInt32 cellColIndex
;
863 cellFrame
->GetColIndex(cellColIndex
);
864 cellColSpan
= aTableFrame
.GetEffectiveColSpan(*cellFrame
);
866 // If the adjacent cell is in a prior row (because of a rowspan) add in the space
867 if ((iter
.IsLeftToRight() && (prevColIndex
!= (cellColIndex
- 1))) ||
868 (!iter
.IsLeftToRight() && (prevColIndex
!= cellColIndex
+ cellColSpan
))) {
869 x
+= GetSpaceBetween(prevColIndex
, cellColIndex
, cellColSpan
, aTableFrame
,
870 cellSpacingX
, iter
.IsLeftToRight(), PR_FALSE
);
873 // remember the rightmost (ltr) or leftmost (rtl) column this cell spans into
874 prevColIndex
= (iter
.IsLeftToRight()) ? cellColIndex
+ (cellColSpan
- 1) : cellColIndex
;
876 // Reflow the child frame
877 nsRect kidRect
= kidFrame
->GetRect();
878 nsRect kidOverflowRect
= kidFrame
->GetOverflowRect();
880 (kidFrame
->GetStateBits() & NS_FRAME_FIRST_REFLOW
) != 0;
883 // Calculate the available width for the table cell using the known column widths
884 nscoord availColWidth
, availCellWidth
;
885 CalcAvailWidth(aTableFrame
, *cellFrame
, cellSpacingX
,
886 availColWidth
, availCellWidth
);
888 nsHTMLReflowMetrics desiredSize
;
890 // If the avail width is not the same as last time we reflowed the cell or
891 // the cell wants to be bigger than what was available last time or
892 // it is a style change reflow or we are printing, then we must reflow the
893 // cell. Otherwise we can skip the reflow.
894 // XXXldb Why is this condition distinct from doReflowChild above?
895 nsSize cellDesiredSize
= cellFrame
->GetDesiredSize();
896 if ((availCellWidth
!= cellFrame
->GetPriorAvailWidth()) ||
897 (cellDesiredSize
.width
> cellFrame
->GetPriorAvailWidth()) ||
898 (GetStateBits() & NS_FRAME_IS_DIRTY
) ||
900 NS_SUBTREE_DIRTY(cellFrame
) ||
901 // See if it needs a special reflow, or if it had one that we need to undo.
902 (cellFrame
->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT
) ||
904 // Reflow the cell to fit the available width, height
905 // XXX The old IR_ChildIsDirty code used availCellWidth here.
906 nsSize
kidAvailSize(availColWidth
, aReflowState
.availableHeight
);
909 nsTableCellReflowState
kidReflowState(aPresContext
, aReflowState
,
910 kidFrame
, kidAvailSize
, PR_FALSE
);
911 InitChildReflowState(*aPresContext
, kidAvailSize
, borderCollapse
,
914 nsReflowStatus status
;
915 rv
= ReflowChild(kidFrame
, aPresContext
, desiredSize
, kidReflowState
,
916 x
, 0, NS_FRAME_INVALIDATE_ON_MOVE
, status
);
918 // allow the table to determine if/how the table needs to be rebalanced
919 // If any of the cells are not complete, then we're not complete
920 if (NS_FRAME_IS_NOT_COMPLETE(status
)) {
921 aStatus
= NS_FRAME_NOT_COMPLETE
;
925 if (x
!= kidRect
.x
) {
926 kidFrame
->InvalidateOverflowRect();
929 desiredSize
.width
= cellDesiredSize
.width
;
930 desiredSize
.height
= cellDesiredSize
.height
;
931 if (cellFrame
->GetStateBits() & NS_FRAME_OUTSIDE_CHILDREN
)
932 desiredSize
.mOverflowArea
= cellFrame
->GetOverflowRect();
934 desiredSize
.mOverflowArea
.SetRect(0, 0, cellDesiredSize
.width
,
935 cellDesiredSize
.height
);
937 // if we are in a floated table, our position is not yet established, so we cannot reposition our views
938 // the containing glock will do this for us after positioning the table
939 if (!aTableFrame
.GetStyleDisplay()->IsFloating()) {
940 // Because we may have moved the frame we need to make sure any views are
941 // positioned properly. We have to do this, because any one of our parent
942 // frames could have moved and we have no way of knowing...
943 nsTableFrame::RePositionViews(kidFrame
);
947 if (NS_UNCONSTRAINEDSIZE
== aReflowState
.availableHeight
) {
948 if (!GetPrevInFlow()) {
949 // Calculate the cell's actual size given its pass2 size. This function
950 // takes into account the specified height (in the style), and any special
951 // logic needed for backwards compatibility
952 CalculateCellActualSize(kidFrame
, desiredSize
.width
,
953 desiredSize
.height
, availCellWidth
);
955 // height may have changed, adjust descent to absorb any excess difference
957 if (!kidFrame
->GetFirstChild(nsnull
)->GetFirstChild(nsnull
))
958 ascent
= desiredSize
.height
;
960 ascent
= ((nsTableCellFrame
*)kidFrame
)->GetCellBaseline();
961 nscoord descent
= desiredSize
.height
- ascent
;
962 UpdateHeight(desiredSize
.height
, ascent
, descent
, &aTableFrame
, cellFrame
);
965 cellMaxHeight
= PR_MAX(cellMaxHeight
, desiredSize
.height
);
966 PRInt32 rowSpan
= aTableFrame
.GetEffectiveRowSpan((nsTableCellFrame
&)*kidFrame
);
968 SetContentHeight(cellMaxHeight
);
973 if (NS_UNCONSTRAINEDSIZE
!= availColWidth
) {
974 desiredSize
.width
= PR_MAX(availCellWidth
, availColWidth
);
977 FinishReflowChild(kidFrame
, aPresContext
, nsnull
, desiredSize
, x
, 0, 0);
979 nsTableFrame::InvalidateFrame(kidFrame
, kidRect
, kidOverflowRect
,
982 x
+= desiredSize
.width
;
985 if (kidRect
.x
!= x
) {
986 // Invalidate the old position
987 kidFrame
->InvalidateOverflowRect();
988 // move to the new position
989 kidFrame
->SetPosition(nsPoint(x
, kidRect
.y
));
990 nsTableFrame::RePositionViews(kidFrame
);
991 // invalidate the new position
992 kidFrame
->InvalidateOverflowRect();
994 // we need to account for the cell's width even if it isn't reflowed
997 if (kidFrame
->GetNextInFlow()) {
998 aStatus
= NS_FRAME_NOT_COMPLETE
;
1001 ConsiderChildOverflow(aDesiredSize
.mOverflowArea
, kidFrame
);
1005 // just set our width to what was available. The table will calculate the width and not use our value.
1006 aDesiredSize
.width
= aReflowState
.availableWidth
;
1008 if (aReflowState
.mFlags
.mSpecialHeightReflow
) {
1009 aDesiredSize
.height
= mRect
.height
;
1011 else if (NS_UNCONSTRAINEDSIZE
== aReflowState
.availableHeight
) {
1012 aDesiredSize
.height
= CalcHeight(aReflowState
);
1013 if (GetPrevInFlow()) {
1014 nscoord height
= CalcHeightFromUnpaginatedHeight(aPresContext
, *this);
1015 aDesiredSize
.height
= PR_MAX(aDesiredSize
.height
, height
);
1018 if (isPaginated
&& HasStyleHeight()) {
1019 // set the unpaginated height so next in flows can try to honor it
1020 SetHasUnpaginatedHeight(PR_TRUE
);
1021 SetUnpaginatedHeight(aPresContext
, aDesiredSize
.height
);
1023 if (isPaginated
&& HasUnpaginatedHeight()) {
1024 aDesiredSize
.height
= PR_MAX(aDesiredSize
.height
, GetUnpaginatedHeight(aPresContext
));
1028 else { // constrained height, paginated
1029 // Compute the height we should have from style (subtracting the
1030 // height from our prev-in-flows from the style height)
1031 nscoord styleHeight
= CalcHeightFromUnpaginatedHeight(aPresContext
, *this);
1032 if (styleHeight
> aReflowState
.availableHeight
) {
1033 styleHeight
= aReflowState
.availableHeight
;
1034 NS_FRAME_SET_INCOMPLETE(aStatus
);
1036 aDesiredSize
.height
= PR_MAX(cellMaxHeight
, styleHeight
);
1038 nsRect
rowRect(0, 0, aDesiredSize
.width
, aDesiredSize
.height
);
1039 aDesiredSize
.mOverflowArea
.UnionRect(aDesiredSize
.mOverflowArea
, rowRect
);
1040 FinishAndStoreOverflow(&aDesiredSize
);
1044 /** Layout the entire row.
1045 * This method stacks cells horizontally according to HTML 4.0 rules.
1048 nsTableRowFrame::Reflow(nsPresContext
* aPresContext
,
1049 nsHTMLReflowMetrics
& aDesiredSize
,
1050 const nsHTMLReflowState
& aReflowState
,
1051 nsReflowStatus
& aStatus
)
1053 DO_GLOBAL_REFLOW_COUNT("nsTableRowFrame");
1054 DISPLAY_REFLOW(aPresContext
, this, aReflowState
, aDesiredSize
, aStatus
);
1055 nsresult rv
= NS_OK
;
1057 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
1059 return NS_ERROR_NULL_POINTER
;
1061 const nsStyleVisibility
* rowVis
= GetStyleVisibility();
1062 PRBool collapseRow
= (NS_STYLE_VISIBILITY_COLLAPSE
== rowVis
->mVisible
);
1064 tableFrame
->SetNeedToCollapse(PR_TRUE
);
1067 // see if a special height reflow needs to occur due to having a pct height
1068 nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState
);
1070 // See if we have a cell with specified/pct height
1071 InitHasCellWithStyleHeight(tableFrame
);
1073 rv
= ReflowChildren(aPresContext
, aDesiredSize
, aReflowState
, *tableFrame
,
1076 // just set our width to what was available. The table will calculate the width and not use our value.
1077 aDesiredSize
.width
= aReflowState
.availableWidth
;
1079 // If our parent is in initial reflow, it'll handle invalidating our
1080 // entire overflow rect.
1081 if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW
)) {
1082 CheckInvalidateSizeChange(aDesiredSize
);
1085 NS_FRAME_SET_TRUNCATION(aStatus
, aReflowState
, aDesiredSize
);
1090 * This function is called by the row group frame's SplitRowGroup() code when
1091 * pushing a row frame that has cell frames that span into it. The cell frame
1092 * should be reflowed with the specified height
1095 nsTableRowFrame::ReflowCellFrame(nsPresContext
* aPresContext
,
1096 const nsHTMLReflowState
& aReflowState
,
1097 PRBool aIsTopOfPage
,
1098 nsTableCellFrame
* aCellFrame
,
1099 nscoord aAvailableHeight
,
1100 nsReflowStatus
& aStatus
)
1102 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
1104 ABORT1(NS_ERROR_NULL_POINTER
);
1106 // Reflow the cell frame with the specified height. Use the existing width
1107 nsRect cellRect
= aCellFrame
->GetRect();
1108 nsRect cellOverflowRect
= aCellFrame
->GetOverflowRect();
1110 nsSize
availSize(cellRect
.width
, aAvailableHeight
);
1111 PRBool borderCollapse
= ((nsTableFrame
*)tableFrame
->GetFirstInFlow())->IsBorderCollapse();
1112 nsTableCellReflowState
cellReflowState(aPresContext
, aReflowState
,
1113 aCellFrame
, availSize
, PR_FALSE
);
1114 InitChildReflowState(*aPresContext
, availSize
, borderCollapse
, cellReflowState
);
1115 cellReflowState
.mFlags
.mIsTopOfPage
= aIsTopOfPage
;
1117 nsHTMLReflowMetrics desiredSize
;
1119 ReflowChild(aCellFrame
, aPresContext
, desiredSize
, cellReflowState
,
1120 0, 0, NS_FRAME_NO_MOVE_FRAME
, aStatus
);
1121 PRBool fullyComplete
= NS_FRAME_IS_COMPLETE(aStatus
) && !NS_FRAME_IS_TRUNCATED(aStatus
);
1122 if (fullyComplete
) {
1123 desiredSize
.height
= aAvailableHeight
;
1125 aCellFrame
->SetSize(nsSize(cellRect
.width
, desiredSize
.height
));
1127 // Note: VerticallyAlignChild can affect the overflow rect.
1128 // XXX What happens if this cell has 'vertical-align: baseline' ?
1129 // XXX Why is it assumed that the cell's ascent hasn't changed ?
1130 if (fullyComplete
) {
1131 aCellFrame
->VerticallyAlignChild(mMaxCellAscent
);
1134 nsTableFrame::InvalidateFrame(aCellFrame
, cellRect
,
1136 (aCellFrame
->GetStateBits() &
1137 NS_FRAME_FIRST_REFLOW
) != 0);
1139 aCellFrame
->DidReflow(aPresContext
, nsnull
, NS_FRAME_REFLOW_FINISHED
);
1141 return desiredSize
.height
;
1145 nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset
,
1147 PRBool aCollapseGroup
,
1148 PRBool
& aDidCollapse
)
1150 const nsStyleVisibility
* rowVis
= GetStyleVisibility();
1151 PRBool collapseRow
= (NS_STYLE_VISIBILITY_COLLAPSE
== rowVis
->mVisible
);
1152 nsTableFrame
* tableFrame
= static_cast<nsTableFrame
*>(nsTableFrame::GetTableFrame(this)->GetFirstInFlow());
1156 tableFrame
->SetNeedToCollapse(PR_TRUE
);
1159 if (aRowOffset
!= 0) {
1160 // We're moving, so invalidate our old position
1161 InvalidateOverflowRect();
1164 nsRect rowRect
= GetRect();
1165 nsRect oldRect
= rowRect
;
1166 nsRect oldOverflowRect
= GetOverflowRect();
1168 rowRect
.y
-= aRowOffset
;
1169 rowRect
.width
= aWidth
;
1170 nsRect
overflowArea(0, 0, 0, 0);
1172 nscoord cellSpacingX
= tableFrame
->GetCellSpacingX();
1173 nscoord cellSpacingY
= tableFrame
->GetCellSpacingY();
1175 if (aCollapseGroup
|| collapseRow
) {
1176 nsTableCellFrame
* cellFrame
= GetFirstCell();
1177 aDidCollapse
= PR_TRUE
;
1178 shift
= rowRect
.height
+ cellSpacingY
;
1180 nsRect cRect
= cellFrame
->GetRect();
1181 // If aRowOffset != 0, there's no point in invalidating the cells, since
1182 // we've already invalidated our overflow area. Note that we _do_ still
1183 // need to invalidate if our row is not moving, because the cell might
1184 // span out of this row, so invalidating our row rect won't do enough.
1185 if (aRowOffset
== 0) {
1189 cellFrame
->SetRect(cRect
);
1190 cellFrame
= cellFrame
->GetNextCell();
1194 else { // row is not collapsed
1195 nsTableIterator
iter(*this);
1196 // remember the col index of the previous cell to handle rowspans into this
1198 PRInt32 firstPrevColIndex
= (iter
.IsLeftToRight()) ? -1 :
1199 tableFrame
->GetColCount();
1200 PRInt32 prevColIndex
= firstPrevColIndex
;
1201 nscoord x
= 0; // running total of children x offset
1203 PRInt32 colIncrement
= iter
.IsLeftToRight() ? 1 : -1;
1205 //nscoord x = cellSpacingX;
1207 nsIFrame
* kidFrame
= iter
.First();
1209 nsIAtom
* frameType
= kidFrame
->GetType();
1210 if (IS_TABLE_CELL(frameType
)) {
1211 nsTableCellFrame
* cellFrame
= (nsTableCellFrame
*)kidFrame
;
1212 PRInt32 cellColIndex
;
1213 cellFrame
->GetColIndex(cellColIndex
);
1214 PRInt32 cellColSpan
= tableFrame
->GetEffectiveColSpan(*cellFrame
);
1216 // If the adjacent cell is in a prior row (because of a rowspan) add in
1218 if ((iter
.IsLeftToRight() && (prevColIndex
!= (cellColIndex
- 1))) ||
1219 (!iter
.IsLeftToRight() &&
1220 (prevColIndex
!= cellColIndex
+ cellColSpan
))) {
1221 x
+= GetSpaceBetween(prevColIndex
, cellColIndex
, cellColSpan
,
1222 *tableFrame
, cellSpacingX
, iter
.IsLeftToRight(),
1225 nsRect
cRect(x
, 0, 0, rowRect
.height
);
1227 // remember the rightmost (ltr) or leftmost (rtl) column this cell
1229 prevColIndex
= (iter
.IsLeftToRight()) ?
1230 cellColIndex
+ (cellColSpan
- 1) : cellColIndex
;
1231 PRInt32 startIndex
= (iter
.IsLeftToRight()) ?
1232 cellColIndex
: cellColIndex
+ (cellColSpan
- 1);
1233 PRInt32 actualColSpan
= cellColSpan
;
1234 PRBool isVisible
= PR_FALSE
;
1235 for (PRInt32 colX
= startIndex
; actualColSpan
> 0;
1236 colX
+= colIncrement
, actualColSpan
--) {
1238 nsTableColFrame
* colFrame
= tableFrame
->GetColFrame(colX
);
1239 const nsStyleVisibility
* colVis
= colFrame
->GetStyleVisibility();
1240 PRBool collapseCol
= (NS_STYLE_VISIBILITY_COLLAPSE
==
1242 nsIFrame
* cgFrame
= colFrame
->GetParent();
1243 const nsStyleVisibility
* groupVis
= cgFrame
->GetStyleVisibility();
1244 PRBool collapseGroup
= (NS_STYLE_VISIBILITY_COLLAPSE
==
1245 groupVis
->mVisible
);
1246 PRBool isCollapsed
= collapseCol
|| collapseGroup
;
1248 tableFrame
->SetNeedToCollapse(PR_TRUE
);
1251 cRect
.width
+= tableFrame
->GetColumnWidth(colX
);
1252 isVisible
= PR_TRUE
;
1254 if (!isCollapsed
&& (actualColSpan
> 1)) {
1255 nsTableColFrame
* nextColFrame
=
1256 tableFrame
->GetColFrame(colX
+ colIncrement
);
1257 const nsStyleVisibility
* nextColVis
=
1258 nextColFrame
->GetStyleVisibility();
1259 if ( (NS_STYLE_VISIBILITY_COLLAPSE
!= nextColVis
->mVisible
) &&
1260 tableFrame
->ColumnHasCellSpacingBefore(colX
+ colIncrement
)) {
1261 cRect
.width
+= cellSpacingX
;
1268 PRInt32 actualRowSpan
= tableFrame
->GetEffectiveRowSpan(*cellFrame
);
1269 nsTableRowFrame
* rowFrame
= GetNextRow();
1270 for (actualRowSpan
--; actualRowSpan
> 0 && rowFrame
; actualRowSpan
--) {
1271 const nsStyleVisibility
* nextRowVis
= rowFrame
->GetStyleVisibility();
1272 PRBool collapseNextRow
= (NS_STYLE_VISIBILITY_COLLAPSE
==
1273 nextRowVis
->mVisible
);
1274 if (!collapseNextRow
) {
1275 nsRect nextRect
= rowFrame
->GetRect();
1276 cRect
.height
+= nextRect
.height
+ cellSpacingY
;
1278 rowFrame
= rowFrame
->GetNextRow();
1281 nsRect oldCellRect
= cellFrame
->GetRect();
1282 nsRect oldCellOverflowRect
= cellFrame
->GetOverflowRect();
1284 if (aRowOffset
== 0 && cRect
.TopLeft() != oldCellRect
.TopLeft()) {
1285 // We're moving the cell. Invalidate the old overflow area
1286 cellFrame
->InvalidateOverflowRect();
1289 cellFrame
->SetRect(cRect
);
1291 // XXXbz This looks completely bogus in the cases when we didn't
1292 // collapse the cell!
1293 nsRect cellOverflow
= nsRect(0, 0, cRect
.width
, cRect
.height
);
1294 cellFrame
->FinishAndStoreOverflow(&cellOverflow
, nsSize(cRect
.width
,
1296 nsTableFrame::RePositionViews(cellFrame
);
1297 ConsiderChildOverflow(overflowArea
, cellFrame
);
1299 if (aRowOffset
== 0) {
1300 nsTableFrame::InvalidateFrame(cellFrame
, oldCellRect
,
1301 oldCellOverflowRect
, PR_FALSE
);
1304 kidFrame
= iter
.Next(); // Get the next child
1309 overflowArea
.UnionRect(nsRect(0,0,rowRect
.width
, rowRect
.height
),
1311 FinishAndStoreOverflow(&overflowArea
, nsSize(rowRect
.width
,
1314 nsTableFrame::RePositionViews(this);
1315 nsTableFrame::InvalidateFrame(this, oldRect
, oldOverflowRect
, PR_FALSE
);
1321 * These 3 functions are called by the row group frame's SplitRowGroup() code when
1322 * it creates a continuing cell frame and wants to insert it into the row's child list
1325 nsTableRowFrame::InsertCellFrame(nsTableCellFrame
* aFrame
,
1326 nsTableCellFrame
* aPrevSibling
)
1328 mFrames
.InsertFrame(nsnull
, aPrevSibling
, aFrame
);
1329 aFrame
->SetParent(this);
1333 nsTableRowFrame::InsertCellFrame(nsTableCellFrame
* aFrame
,
1336 // Find the cell frame where col index < aColIndex
1337 nsTableCellFrame
* priorCell
= nsnull
;
1338 for (nsIFrame
* child
= mFrames
.FirstChild(); child
;
1339 child
= child
->GetNextSibling()) {
1340 if (!IS_TABLE_CELL(child
->GetType())) {
1341 nsTableCellFrame
* cellFrame
= (nsTableCellFrame
*)child
;
1343 cellFrame
->GetColIndex(colIndex
);
1344 if (colIndex
< aColIndex
) {
1345 priorCell
= cellFrame
;
1350 InsertCellFrame(aFrame
, priorCell
);
1354 nsTableRowFrame::RemoveCellFrame(nsTableCellFrame
* aFrame
)
1356 if (!mFrames
.RemoveFrame(aFrame
))
1357 NS_ASSERTION(PR_FALSE
, "frame not in list");
1361 nsTableRowFrame::GetType() const
1363 return nsGkAtoms::tableRowFrame
;
1367 nsTableRowFrame::GetNextRow() const
1369 nsIFrame
* childFrame
= GetNextSibling();
1370 while (childFrame
) {
1371 if (nsGkAtoms::tableRowFrame
== childFrame
->GetType()) {
1372 NS_ASSERTION(NS_STYLE_DISPLAY_TABLE_ROW
== childFrame
->GetStyleDisplay()->mDisplay
, "wrong display type on rowframe");
1373 return (nsTableRowFrame
*)childFrame
;
1375 childFrame
= childFrame
->GetNextSibling();
1381 nsTableRowFrame::SetUnpaginatedHeight(nsPresContext
* aPresContext
,
1384 NS_ASSERTION(!GetPrevInFlow(), "program error");
1386 nscoord
* value
= (nscoord
*)nsTableFrame::GetProperty(this, nsGkAtoms::rowUnpaginatedHeightProperty
, PR_TRUE
);
1393 nsTableRowFrame::GetUnpaginatedHeight(nsPresContext
* aPresContext
)
1395 // See if the property is set
1396 nscoord
* value
= (nscoord
*)nsTableFrame::GetProperty(GetFirstInFlow(), nsGkAtoms::rowUnpaginatedHeightProperty
);
1403 void nsTableRowFrame::SetContinuousBCBorderWidth(PRUint8 aForSide
,
1404 BCPixelSize aPixelValue
)
1408 mRightContBorderWidth
= aPixelValue
;
1411 mTopContBorderWidth
= aPixelValue
;
1414 mLeftContBorderWidth
= aPixelValue
;
1417 NS_ERROR("invalid NS_SIDE arg");
1422 * Sets the NS_ROW_HAS_CELL_WITH_STYLE_HEIGHT bit to indicate whether
1423 * this row has any cells that have non-auto-height. (Row-spanning
1424 * cells are ignored.)
1426 void nsTableRowFrame::InitHasCellWithStyleHeight(nsTableFrame
* aTableFrame
)
1428 nsTableIterator
iter(*this);
1430 for (nsIFrame
* kidFrame
= iter
.First(); kidFrame
; kidFrame
= iter
.Next()) {
1431 nsIAtom
* frameType
= kidFrame
->GetType();
1432 if (!IS_TABLE_CELL(frameType
)) {
1433 NS_NOTREACHED("Table row has a non-cell child.");
1436 nsTableCellFrame
* cellFrame
= static_cast<nsTableCellFrame
*>(kidFrame
);
1437 // Ignore row-spanning cells
1438 if (aTableFrame
->GetEffectiveRowSpan(*cellFrame
) == 1 &&
1439 cellFrame
->GetStylePosition()->mHeight
.GetUnit() != eStyleUnit_Auto
) {
1440 AddStateBits(NS_ROW_HAS_CELL_WITH_STYLE_HEIGHT
);
1444 RemoveStateBits(NS_ROW_HAS_CELL_WITH_STYLE_HEIGHT
);
1447 /* ----- global methods ----- */
1450 NS_NewTableRowFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
1452 return new (aPresShell
) nsTableRowFrame(aContext
);
1457 nsTableRowFrame::GetFrameName(nsAString
& aResult
) const
1459 return MakeFrameName(NS_LITERAL_STRING("TableRow"), aResult
);