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 using namespace mozilla
;
57 struct nsTableCellReflowState
: public nsHTMLReflowState
59 nsTableCellReflowState(nsPresContext
* aPresContext
,
60 const nsHTMLReflowState
& aParentReflowState
,
62 const nsSize
& aAvailableSpace
,
63 PRBool aInit
= PR_TRUE
)
64 : nsHTMLReflowState(aPresContext
, aParentReflowState
, aFrame
,
65 aAvailableSpace
, -1, -1, aInit
)
69 void FixUp(const nsSize
& aAvailSpace
);
72 void nsTableCellReflowState::FixUp(const nsSize
& aAvailSpace
)
74 // fix the mComputed values during a pass 2 reflow since the cell can be a percentage base
75 NS_WARN_IF_FALSE(NS_UNCONSTRAINEDSIZE
!= aAvailSpace
.width
,
76 "have unconstrained width; this should only result from "
77 "very large sizes, not attempts at intrinsic width "
79 if (NS_UNCONSTRAINEDSIZE
!= ComputedWidth()) {
80 nscoord computedWidth
=
81 aAvailSpace
.width
- mComputedBorderPadding
.LeftRight();
82 computedWidth
= NS_MAX(0, computedWidth
);
83 SetComputedWidth(computedWidth
);
85 if (NS_UNCONSTRAINEDSIZE
!= ComputedHeight() &&
86 NS_UNCONSTRAINEDSIZE
!= aAvailSpace
.height
) {
87 nscoord computedHeight
=
88 aAvailSpace
.height
- mComputedBorderPadding
.TopBottom();
89 computedHeight
= NS_MAX(0, computedHeight
);
90 SetComputedHeight(computedHeight
);
95 nsTableRowFrame::InitChildReflowState(nsPresContext
& aPresContext
,
96 const nsSize
& aAvailSize
,
97 PRBool aBorderCollapse
,
98 nsTableCellReflowState
& aReflowState
)
100 nsMargin collapseBorder
;
101 nsMargin
* pCollapseBorder
= nsnull
;
102 if (aBorderCollapse
) {
103 // we only reflow cells, so don't need to check frame type
104 nsBCTableCellFrame
* bcCellFrame
= (nsBCTableCellFrame
*)aReflowState
.frame
;
106 pCollapseBorder
= bcCellFrame
->GetBorderWidth(collapseBorder
);
109 aReflowState
.Init(&aPresContext
, -1, -1, pCollapseBorder
);
110 aReflowState
.FixUp(aAvailSize
);
114 nsTableRowFrame::SetFixedHeight(nscoord aValue
)
116 nscoord height
= NS_MAX(0, aValue
);
117 if (HasFixedHeight()) {
118 if (height
> mStyleFixedHeight
) {
119 mStyleFixedHeight
= height
;
123 mStyleFixedHeight
= height
;
125 SetHasFixedHeight(PR_TRUE
);
131 nsTableRowFrame::SetPctHeight(float aPctValue
,
134 nscoord height
= NS_MAX(0, NSToCoordRound(aPctValue
* 100.0f
));
135 if (HasPctHeight()) {
136 if ((height
> mStylePctHeight
) || aForce
) {
137 mStylePctHeight
= height
;
141 mStylePctHeight
= height
;
143 SetHasPctHeight(PR_TRUE
);
148 /* ----------- nsTableRowFrame ---------- */
150 NS_QUERYFRAME_HEAD(nsTableRowFrame
)
151 NS_QUERYFRAME_ENTRY(nsTableRowFrame
)
152 NS_QUERYFRAME_TAIL_INHERITING(nsHTMLContainerFrame
)
154 nsTableRowFrame::nsTableRowFrame(nsStyleContext
* aContext
)
155 : nsHTMLContainerFrame(aContext
)
157 mBits
.mRowIndex
= mBits
.mFirstInserted
= 0;
161 nsTableRowFrame::~nsTableRowFrame()
166 nsTableRowFrame::Init(nsIContent
* aContent
,
168 nsIFrame
* aPrevInFlow
)
172 // Let the base class do its initialization
173 rv
= nsHTMLContainerFrame::Init(aContent
, aParent
, aPrevInFlow
);
175 NS_ASSERTION(NS_STYLE_DISPLAY_TABLE_ROW
== GetStyleDisplay()->mDisplay
,
176 "wrong display on table row frame");
180 nsTableRowFrame
* rowFrame
= (nsTableRowFrame
*)aPrevInFlow
;
182 SetRowIndex(rowFrame
->GetRowIndex());
189 nsTableRowFrame::DidSetStyleContext(nsStyleContext
* aOldStyleContext
)
191 if (!aOldStyleContext
) //avoid this on init
194 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
196 if (tableFrame
->IsBorderCollapse() &&
197 tableFrame
->BCRecalcNeeded(aOldStyleContext
, GetStyleContext())) {
198 nsRect
damageArea(0, GetRowIndex(), tableFrame
->GetColCount(), 1);
199 tableFrame
->SetBCDamageArea(damageArea
);
205 nsTableRowFrame::AppendFrames(nsIAtom
* aListName
,
206 nsFrameList
& aFrameList
)
208 NS_ASSERTION(!aListName
, "unexpected child list");
211 // XXXbz why do we append here first, then append to table, while
212 // for InsertFrames we do it in the other order? Bug 507419 covers this.
213 const nsFrameList::Slice
& newCells
= mFrames
.AppendFrames(nsnull
, aFrameList
);
215 // Add the new cell frames to the table
216 nsTableFrame
*tableFrame
= nsTableFrame::GetTableFrame(this);
217 for (nsFrameList::Enumerator
e(newCells
) ; !e
.AtEnd(); e
.Next()) {
218 nsTableCellFrame
*cellFrame
= do_QueryFrame(e
.get());
219 NS_ASSERTION(cellFrame
, "Unexpected frame");
221 // Add the cell to the cell map
222 tableFrame
->AppendCell(*cellFrame
, GetRowIndex());
226 PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange
,
227 NS_FRAME_HAS_DIRTY_CHILDREN
);
228 tableFrame
->SetGeometryDirty();
235 nsTableRowFrame::InsertFrames(nsIAtom
* aListName
,
236 nsIFrame
* aPrevFrame
,
237 nsFrameList
& aFrameList
)
239 NS_ASSERTION(!aListName
, "unexpected child list");
240 NS_ASSERTION(!aPrevFrame
|| aPrevFrame
->GetParent() == this,
241 "inserting after sibling frame with different parent");
243 // Get the table frame
244 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
246 // gather the new frames (only those which are cells) into an array
247 // XXXbz there shouldn't be any other ones here... can we just put
248 // them all in the array and not do all this QI nonsense?
249 nsIAtom
* cellFrameType
= (tableFrame
->IsBorderCollapse()) ? nsGkAtoms::bcTableCellFrame
: nsGkAtoms::tableCellFrame
;
250 nsTableCellFrame
* prevCellFrame
= (nsTableCellFrame
*)nsTableFrame::GetFrameAtOrBefore(this, aPrevFrame
, cellFrameType
);
251 nsTArray
<nsTableCellFrame
*> cellChildren
;
252 for (nsFrameList::Enumerator
e(aFrameList
); !e
.AtEnd(); e
.Next()) {
253 nsTableCellFrame
*cellFrame
= do_QueryFrame(e
.get());
254 NS_ASSERTION(cellFrame
, "Unexpected frame");
256 cellChildren
.AppendElement(cellFrame
);
259 // insert the cells into the cell map
260 PRInt32 colIndex
= -1;
262 prevCellFrame
->GetColIndex(colIndex
);
264 tableFrame
->InsertCells(cellChildren
, GetRowIndex(), colIndex
);
266 // Insert the frames in the frame list
267 mFrames
.InsertFrames(nsnull
, aPrevFrame
, aFrameList
);
269 PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange
,
270 NS_FRAME_HAS_DIRTY_CHILDREN
);
271 tableFrame
->SetGeometryDirty();
277 nsTableRowFrame::RemoveFrame(nsIAtom
* aListName
,
280 NS_ASSERTION(!aListName
, "unexpected child list");
282 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
284 nsTableCellFrame
*cellFrame
= do_QueryFrame(aOldFrame
);
287 cellFrame
->GetColIndex(colIndex
);
288 // remove the cell from the cell map
289 tableFrame
->RemoveCell(cellFrame
, GetRowIndex());
291 // Remove the frame and destroy it
292 mFrames
.DestroyFrame(aOldFrame
);
294 PresContext()->PresShell()->
295 FrameNeedsReflow(this, nsIPresShell::eTreeChange
,
296 NS_FRAME_HAS_DIRTY_CHILDREN
);
297 tableFrame
->SetGeometryDirty();
300 NS_ERROR("unexpected frame type");
301 return NS_ERROR_INVALID_ARG
;
308 /* virtual */ nsMargin
309 nsTableRowFrame::GetUsedMargin() const
311 return nsMargin(0,0,0,0);
314 /* virtual */ nsMargin
315 nsTableRowFrame::GetUsedBorder() const
317 return nsMargin(0,0,0,0);
320 /* virtual */ nsMargin
321 nsTableRowFrame::GetUsedPadding() const
323 return nsMargin(0,0,0,0);
327 GetHeightOfRowsSpannedBelowFirst(nsTableCellFrame
& aTableCellFrame
,
328 nsTableFrame
& aTableFrame
)
331 nscoord cellSpacingY
= aTableFrame
.GetCellSpacingY();
332 PRInt32 rowSpan
= aTableFrame
.GetEffectiveRowSpan(aTableCellFrame
);
333 // add in height of rows spanned beyond the 1st one
334 nsIFrame
* nextRow
= aTableCellFrame
.GetParent()->GetNextSibling();
335 for (PRInt32 rowX
= 1; ((rowX
< rowSpan
) && nextRow
);) {
336 if (nsGkAtoms::tableRowFrame
== nextRow
->GetType()) {
337 height
+= nextRow
->GetSize().height
;
340 height
+= cellSpacingY
;
341 nextRow
= nextRow
->GetNextSibling();
347 nsTableRowFrame::GetFirstCell()
349 nsIFrame
* childFrame
= mFrames
.FirstChild();
351 nsTableCellFrame
*cellFrame
= do_QueryFrame(childFrame
);
355 childFrame
= childFrame
->GetNextSibling();
361 * Post-reflow hook. This is where the table row does its post-processing
364 nsTableRowFrame::DidResize()
366 // Resize and re-align the cell frames based on our row height
367 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
371 nsTableIterator
iter(*this);
372 nsIFrame
* childFrame
= iter
.First();
374 nsHTMLReflowMetrics desiredSize
;
375 desiredSize
.width
= mRect
.width
;
376 desiredSize
.height
= mRect
.height
;
377 desiredSize
.mOverflowArea
= nsRect(0, 0, desiredSize
.width
,
381 nsTableCellFrame
*cellFrame
= do_QueryFrame(childFrame
);
383 nscoord cellHeight
= mRect
.height
+ GetHeightOfRowsSpannedBelowFirst(*cellFrame
, *tableFrame
);
385 // resize the cell's height
386 nsRect cellRect
= cellFrame
->GetRect();
387 nsRect cellOverflowRect
= cellFrame
->GetOverflowRect();
388 if (cellRect
.height
!= cellHeight
)
390 cellFrame
->SetSize(nsSize(cellRect
.width
, cellHeight
));
391 nsTableFrame::InvalidateFrame(cellFrame
, cellRect
, cellOverflowRect
,
395 // realign cell content based on the new height. We might be able to
396 // skip this if the height didn't change... maybe. Hard to tell.
397 cellFrame
->VerticallyAlignChild(mMaxCellAscent
);
399 // Always store the overflow, even if the height didn't change, since
400 // we'll lose part of our overflow area otherwise.
401 ConsiderChildOverflow(desiredSize
.mOverflowArea
, cellFrame
);
403 // Note that if the cell's *content* needs to change in response
404 // to this height, it will get a special height reflow.
406 // Get the next child
407 childFrame
= iter
.Next();
409 FinishAndStoreOverflow(&desiredSize
);
411 nsContainerFrame::SyncFrameViewAfterReflow(PresContext(), this, GetView(), &desiredSize
.mOverflowArea
, 0);
413 // Let our base class do the usual work
416 // returns max-ascent amongst all cells that have 'vertical-align: baseline'
417 // *including* cells with rowspans
418 nscoord
nsTableRowFrame::GetMaxCellAscent() const
420 return mMaxCellAscent
;
423 nscoord
nsTableRowFrame::GetRowBaseline()
426 return mMaxCellAscent
;
428 // If we don't have a baseline on any of the cells we go for the lowest
429 // content edge of the inner block frames.
430 // Every table cell has a cell frame with its border and padding. Inside
431 // the cell is a block frame. The cell is as high as the tallest cell in
432 // the parent row. As a consequence the block frame might not touch both
433 // the top and the bottom padding of it parent cell frame at the same time.
435 // bbbbbbbbbbbbbbbbbb cell border: b
436 // bppppppppppppppppb cell padding: p
437 // bpxxxxxxxxxxxxxxpb inner block: x
441 // bpxxxxxxxxxxxxxxpb base line
444 // bppppppppppppppppb
445 // bbbbbbbbbbbbbbbbbb
447 nsTableIterator
iter(*this);
448 nsIFrame
* childFrame
= iter
.First();
451 if (IS_TABLE_CELL(childFrame
->GetType())) {
452 nsIFrame
* firstKid
= childFrame
->GetFirstChild(nsnull
);
453 ascent
= NS_MAX(ascent
, firstKid
->GetRect().YMost());
455 // Get the next child
456 childFrame
= iter
.Next();
461 nsTableRowFrame::GetHeight(nscoord aPctBasis
) const
464 if ((aPctBasis
> 0) && HasPctHeight()) {
465 height
= NSToCoordRound(GetPctHeight() * (float)aPctBasis
);
467 if (HasFixedHeight()) {
468 height
= NS_MAX(height
, GetFixedHeight());
470 return NS_MAX(height
, GetContentHeight());
474 nsTableRowFrame::ResetHeight(nscoord aFixedHeight
)
476 SetHasFixedHeight(PR_FALSE
);
477 SetHasPctHeight(PR_FALSE
);
482 if (aFixedHeight
> 0) {
483 SetFixedHeight(aFixedHeight
);
491 nsTableRowFrame::UpdateHeight(nscoord aHeight
,
494 nsTableFrame
* aTableFrame
,
495 nsTableCellFrame
* aCellFrame
)
497 if (!aTableFrame
|| !aCellFrame
) {
498 NS_ASSERTION(PR_FALSE
, "invalid call");
502 if (aHeight
!= NS_UNCONSTRAINEDSIZE
) {
503 if (!(aCellFrame
->HasVerticalAlignBaseline())) { // only the cell's height matters
504 if (GetHeight() < aHeight
) {
505 PRInt32 rowSpan
= aTableFrame
->GetEffectiveRowSpan(*aCellFrame
);
507 SetContentHeight(aHeight
);
511 else { // the alignment on the baseline can change the height
512 NS_ASSERTION((aAscent
!= NS_UNCONSTRAINEDSIZE
) && (aDescent
!= NS_UNCONSTRAINEDSIZE
), "invalid call");
513 // see if this is a long ascender
514 if (mMaxCellAscent
< aAscent
) {
515 mMaxCellAscent
= aAscent
;
517 // see if this is a long descender and without rowspan
518 if (mMaxCellDescent
< aDescent
) {
519 PRInt32 rowSpan
= aTableFrame
->GetEffectiveRowSpan(*aCellFrame
);
521 mMaxCellDescent
= aDescent
;
524 // keep the tallest height in sync
525 if (GetHeight() < mMaxCellAscent
+ mMaxCellDescent
) {
526 SetContentHeight(mMaxCellAscent
+ mMaxCellDescent
);
533 nsTableRowFrame::CalcHeight(const nsHTMLReflowState
& aReflowState
)
535 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
539 nscoord computedHeight
= (NS_UNCONSTRAINEDSIZE
== aReflowState
.ComputedHeight())
540 ? 0 : aReflowState
.ComputedHeight();
541 ResetHeight(computedHeight
);
543 const nsStylePosition
* position
= GetStylePosition();
544 if (eStyleUnit_Coord
== position
->mHeight
.GetUnit()) {
545 SetFixedHeight(position
->mHeight
.GetCoordValue());
547 else if (eStyleUnit_Percent
== position
->mHeight
.GetUnit()) {
548 SetPctHeight(position
->mHeight
.GetPercentValue());
551 for (nsIFrame
* kidFrame
= mFrames
.FirstChild(); kidFrame
;
552 kidFrame
= kidFrame
->GetNextSibling()) {
553 nsTableCellFrame
*cellFrame
= do_QueryFrame(kidFrame
);
555 nsSize desSize
= cellFrame
->GetDesiredSize();
556 if ((NS_UNCONSTRAINEDSIZE
== aReflowState
.availableHeight
) && !GetPrevInFlow()) {
557 CalculateCellActualHeight(cellFrame
, desSize
.height
);
559 // height may have changed, adjust descent to absorb any excess difference
561 if (!kidFrame
->GetFirstChild(nsnull
)->GetFirstChild(nsnull
))
562 ascent
= desSize
.height
;
564 ascent
= cellFrame
->GetCellBaseline();
565 nscoord descent
= desSize
.height
- ascent
;
566 UpdateHeight(desSize
.height
, ascent
, descent
, tableFrame
, cellFrame
);
573 * We need a custom display item for table row backgrounds. This is only used
574 * when the table row is the root of a stacking context (e.g., has 'opacity').
575 * Table row backgrounds can extend beyond the row frame bounds, when
576 * the row contains row-spanning cells.
578 class nsDisplayTableRowBackground
: public nsDisplayTableItem
{
580 nsDisplayTableRowBackground(nsTableRowFrame
* aFrame
) : nsDisplayTableItem(aFrame
) {
581 MOZ_COUNT_CTOR(nsDisplayTableRowBackground
);
583 #ifdef NS_BUILD_REFCNT_LOGGING
584 virtual ~nsDisplayTableRowBackground() {
585 MOZ_COUNT_DTOR(nsDisplayTableRowBackground
);
589 virtual void Paint(nsDisplayListBuilder
* aBuilder
,
590 nsIRenderingContext
* aCtx
);
591 NS_DISPLAY_DECL_NAME("TableRowBackground")
595 nsDisplayTableRowBackground::Paint(nsDisplayListBuilder
* aBuilder
,
596 nsIRenderingContext
* aCtx
) {
597 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(mFrame
);
599 nsPoint pt
= aBuilder
->ToReferenceFrame(mFrame
);
600 TableBackgroundPainter
painter(tableFrame
,
601 TableBackgroundPainter::eOrigin_TableRow
,
602 mFrame
->PresContext(), *aCtx
,
604 aBuilder
->GetBackgroundPaintFlags());
605 painter
.PaintRow(static_cast<nsTableRowFrame
*>(mFrame
));
609 nsTableRowFrame::BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
610 const nsRect
& aDirtyRect
,
611 const nsDisplayListSet
& aLists
)
613 if (!IsVisibleInSelection(aBuilder
))
616 PRBool isRoot
= aBuilder
->IsAtRootOfPseudoStackingContext();
617 nsDisplayTableItem
* item
= nsnull
;
619 // This background is created regardless of whether this frame is
620 // visible or not. Visibility decisions are delegated to the
621 // table background painter.
622 // We would use nsDisplayGeneric for this rare case except that we
623 // need the background to be larger than the row frame in some
625 item
= new (aBuilder
) nsDisplayTableRowBackground(this);
626 nsresult rv
= aLists
.BorderBackground()->AppendNewToTop(item
);
627 NS_ENSURE_SUCCESS(rv
, rv
);
630 return nsTableFrame::DisplayGenericTablePart(aBuilder
, this, aDirtyRect
, aLists
, item
);
634 nsTableRowFrame::GetSkipSides() const
637 if (nsnull
!= GetPrevInFlow()) {
638 skip
|= 1 << NS_SIDE_TOP
;
640 if (nsnull
!= GetNextInFlow()) {
641 skip
|= 1 << NS_SIDE_BOTTOM
;
646 // Calculate the cell's actual height given its pass2 height.
647 // Takes into account the specified height (in the style).
648 // Modifies the desired height that is passed in.
650 nsTableRowFrame::CalculateCellActualHeight(nsTableCellFrame
* aCellFrame
,
651 nscoord
& aDesiredHeight
)
653 nscoord specifiedHeight
= 0;
655 // Get the height specified in the style information
656 const nsStylePosition
* position
= aCellFrame
->GetStylePosition();
658 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
660 return NS_ERROR_NULL_POINTER
;
662 PRInt32 rowSpan
= tableFrame
->GetEffectiveRowSpan(*aCellFrame
);
664 switch (position
->mHeight
.GetUnit()) {
665 case eStyleUnit_Coord
:
666 specifiedHeight
= position
->mHeight
.GetCoordValue();
668 SetFixedHeight(specifiedHeight
);
670 case eStyleUnit_Percent
: {
672 SetPctHeight(position
->mHeight
.GetPercentValue());
673 // pct heights are handled when all of the cells are finished, so don't set specifiedHeight
676 case eStyleUnit_Auto
:
681 // If the specified height is greater than the desired height, then use the specified height
682 if (specifiedHeight
> aDesiredHeight
)
683 aDesiredHeight
= specifiedHeight
;
688 // Calculates the available width for the table cell based on the known
689 // column widths taking into account column spans and column spacing
691 CalcAvailWidth(nsTableFrame
& aTableFrame
,
692 nsTableCellFrame
& aCellFrame
,
693 nscoord aCellSpacingX
)
695 nscoord cellAvailWidth
= 0;
697 aCellFrame
.GetColIndex(colIndex
);
698 PRInt32 colspan
= aTableFrame
.GetEffectiveColSpan(aCellFrame
);
699 NS_ASSERTION(colspan
> 0, "effective colspan should be positive");
701 for (PRInt32 spanX
= 0; spanX
< colspan
; spanX
++) {
702 cellAvailWidth
+= aTableFrame
.GetColumnWidth(colIndex
+ spanX
);
704 aTableFrame
.ColumnHasCellSpacingBefore(colIndex
+ spanX
)) {
705 cellAvailWidth
+= aCellSpacingX
;
708 return cellAvailWidth
;
712 GetSpaceBetween(PRInt32 aPrevColIndex
,
715 nsTableFrame
& aTableFrame
,
716 nscoord aCellSpacingX
,
717 PRBool aIsLeftToRight
,
718 PRBool aCheckVisibility
)
722 if (aIsLeftToRight
) {
723 for (colX
= aPrevColIndex
+ 1; aColIndex
> colX
; colX
++) {
724 PRBool isCollapsed
= PR_FALSE
;
725 if (!aCheckVisibility
) {
726 space
+= aTableFrame
.GetColumnWidth(colX
);
729 nsTableColFrame
* colFrame
= aTableFrame
.GetColFrame(colX
);
730 const nsStyleVisibility
* colVis
= colFrame
->GetStyleVisibility();
731 PRBool collapseCol
= (NS_STYLE_VISIBILITY_COLLAPSE
== colVis
->mVisible
);
732 nsIFrame
* cgFrame
= colFrame
->GetParent();
733 const nsStyleVisibility
* groupVis
= cgFrame
->GetStyleVisibility();
734 PRBool collapseGroup
= (NS_STYLE_VISIBILITY_COLLAPSE
==
736 isCollapsed
= collapseCol
|| collapseGroup
;
738 space
+= aTableFrame
.GetColumnWidth(colX
);
740 if (!isCollapsed
&& aTableFrame
.ColumnHasCellSpacingBefore(colX
)) {
741 space
+= aCellSpacingX
;
746 PRInt32 lastCol
= aColIndex
+ aColSpan
- 1;
747 for (colX
= aPrevColIndex
- 1; colX
> lastCol
; colX
--) {
748 PRBool isCollapsed
= PR_FALSE
;
749 if (!aCheckVisibility
) {
750 space
+= aTableFrame
.GetColumnWidth(colX
);
753 nsTableColFrame
* colFrame
= aTableFrame
.GetColFrame(colX
);
754 const nsStyleVisibility
* colVis
= colFrame
->GetStyleVisibility();
755 PRBool collapseCol
= (NS_STYLE_VISIBILITY_COLLAPSE
== colVis
->mVisible
);
756 nsIFrame
* cgFrame
= colFrame
->GetParent();
757 const nsStyleVisibility
* groupVis
= cgFrame
->GetStyleVisibility();
758 PRBool collapseGroup
= (NS_STYLE_VISIBILITY_COLLAPSE
==
760 isCollapsed
= collapseCol
|| collapseGroup
;
762 space
+= aTableFrame
.GetColumnWidth(colX
);
764 if (!isCollapsed
&& aTableFrame
.ColumnHasCellSpacingBefore(colX
)) {
765 space
+= aCellSpacingX
;
772 // subtract the heights of aRow's prev in flows from the unpaginated height
774 nscoord
CalcHeightFromUnpaginatedHeight(nsPresContext
* aPresContext
,
775 nsTableRowFrame
& aRow
)
778 nsTableRowFrame
* firstInFlow
= (nsTableRowFrame
*)aRow
.GetFirstInFlow();
779 if (!firstInFlow
) ABORT1(0);
780 if (firstInFlow
->HasUnpaginatedHeight()) {
781 height
= firstInFlow
->GetUnpaginatedHeight(aPresContext
);
782 for (nsIFrame
* prevInFlow
= aRow
.GetPrevInFlow(); prevInFlow
;
783 prevInFlow
= prevInFlow
->GetPrevInFlow()) {
784 height
-= prevInFlow
->GetSize().height
;
787 return NS_MAX(height
, 0);
791 nsTableRowFrame::ReflowChildren(nsPresContext
* aPresContext
,
792 nsHTMLReflowMetrics
& aDesiredSize
,
793 const nsHTMLReflowState
& aReflowState
,
794 nsTableFrame
& aTableFrame
,
795 nsReflowStatus
& aStatus
)
797 aStatus
= NS_FRAME_COMPLETE
;
799 PRBool borderCollapse
= (((nsTableFrame
*)aTableFrame
.GetFirstInFlow())->IsBorderCollapse());
801 // XXXldb Should we be checking constrained height instead?
802 PRBool isPaginated
= aPresContext
->IsPaginated();
806 nscoord cellSpacingX
= aTableFrame
.GetCellSpacingX();
807 PRInt32 cellColSpan
= 1; // must be defined here so it's set properly for non-cell kids
809 nsTableIterator
iter(*this);
810 // remember the col index of the previous cell to handle rowspans into this row
811 PRInt32 firstPrevColIndex
= (iter
.IsLeftToRight()) ? -1 : aTableFrame
.GetColCount();
812 PRInt32 prevColIndex
= firstPrevColIndex
;
813 nscoord x
= 0; // running total of children x offset
815 // This computes the max of all cell heights
816 nscoord cellMaxHeight
= 0;
818 // Reflow each of our existing cell frames
819 for (nsIFrame
* kidFrame
= iter
.First(); kidFrame
; kidFrame
= iter
.Next()) {
820 nsTableCellFrame
*cellFrame
= do_QueryFrame(kidFrame
);
822 // XXXldb nsCSSFrameConstructor needs to enforce this!
823 NS_NOTREACHED("yikes, a non-row child");
825 // it's an unknown frame type, give it a generic reflow and ignore the results
826 nsTableCellReflowState
kidReflowState(aPresContext
, aReflowState
,
827 kidFrame
, nsSize(0,0), PR_FALSE
);
828 InitChildReflowState(*aPresContext
, nsSize(0,0), PR_FALSE
, kidReflowState
);
829 nsHTMLReflowMetrics desiredSize
;
830 nsReflowStatus status
;
831 ReflowChild(kidFrame
, aPresContext
, desiredSize
, kidReflowState
, 0, 0, 0, status
);
832 kidFrame
->DidReflow(aPresContext
, nsnull
, NS_FRAME_REFLOW_FINISHED
);
837 // See if we should only reflow the dirty child frames
838 PRBool doReflowChild
= PR_TRUE
;
839 if (!aReflowState
.ShouldReflowAllKids() &&
840 !aTableFrame
.IsGeometryDirty() &&
841 !NS_SUBTREE_DIRTY(kidFrame
)) {
842 if (!aReflowState
.mFlags
.mSpecialHeightReflow
)
843 doReflowChild
= PR_FALSE
;
845 else if ((NS_UNCONSTRAINEDSIZE
!= aReflowState
.availableHeight
)) {
846 // We don't reflow a rowspan >1 cell here with a constrained height.
847 // That happens in nsTableRowGroupFrame::SplitSpanningCells.
848 if (aTableFrame
.GetEffectiveRowSpan(*cellFrame
) > 1) {
849 doReflowChild
= PR_FALSE
;
852 if (aReflowState
.mFlags
.mSpecialHeightReflow
) {
853 if (!isPaginated
&& !(cellFrame
->GetStateBits() &
854 NS_FRAME_CONTAINS_RELATIVE_HEIGHT
)) {
859 PRInt32 cellColIndex
;
860 cellFrame
->GetColIndex(cellColIndex
);
861 cellColSpan
= aTableFrame
.GetEffectiveColSpan(*cellFrame
);
863 // If the adjacent cell is in a prior row (because of a rowspan) add in the space
864 if ((iter
.IsLeftToRight() && (prevColIndex
!= (cellColIndex
- 1))) ||
865 (!iter
.IsLeftToRight() && (prevColIndex
!= cellColIndex
+ cellColSpan
))) {
866 x
+= GetSpaceBetween(prevColIndex
, cellColIndex
, cellColSpan
, aTableFrame
,
867 cellSpacingX
, iter
.IsLeftToRight(), PR_FALSE
);
870 // remember the rightmost (ltr) or leftmost (rtl) column this cell spans into
871 prevColIndex
= (iter
.IsLeftToRight()) ? cellColIndex
+ (cellColSpan
- 1) : cellColIndex
;
873 // Reflow the child frame
874 nsRect kidRect
= kidFrame
->GetRect();
875 nsRect kidOverflowRect
= kidFrame
->GetOverflowRect();
877 (kidFrame
->GetStateBits() & NS_FRAME_FIRST_REFLOW
) != 0;
880 // Calculate the available width for the table cell using the known column widths
881 nscoord availCellWidth
=
882 CalcAvailWidth(aTableFrame
, *cellFrame
, cellSpacingX
);
884 nsHTMLReflowMetrics desiredSize
;
886 // If the avail width is not the same as last time we reflowed the cell or
887 // the cell wants to be bigger than what was available last time or
888 // it is a style change reflow or we are printing, then we must reflow the
889 // cell. Otherwise we can skip the reflow.
890 // XXXldb Why is this condition distinct from doReflowChild above?
891 nsSize cellDesiredSize
= cellFrame
->GetDesiredSize();
892 if ((availCellWidth
!= cellFrame
->GetPriorAvailWidth()) ||
893 (cellDesiredSize
.width
> cellFrame
->GetPriorAvailWidth()) ||
894 (GetStateBits() & NS_FRAME_IS_DIRTY
) ||
896 NS_SUBTREE_DIRTY(cellFrame
) ||
897 // See if it needs a special reflow, or if it had one that we need to undo.
898 (cellFrame
->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT
) ||
900 // Reflow the cell to fit the available width, height
901 // XXX The old IR_ChildIsDirty code used availCellWidth here.
902 nsSize
kidAvailSize(availCellWidth
, aReflowState
.availableHeight
);
905 nsTableCellReflowState
kidReflowState(aPresContext
, aReflowState
,
906 kidFrame
, kidAvailSize
, PR_FALSE
);
907 InitChildReflowState(*aPresContext
, kidAvailSize
, borderCollapse
,
910 nsReflowStatus status
;
911 rv
= ReflowChild(kidFrame
, aPresContext
, desiredSize
, kidReflowState
,
912 x
, 0, NS_FRAME_INVALIDATE_ON_MOVE
, status
);
914 // allow the table to determine if/how the table needs to be rebalanced
915 // If any of the cells are not complete, then we're not complete
916 if (NS_FRAME_IS_NOT_COMPLETE(status
)) {
917 aStatus
= NS_FRAME_NOT_COMPLETE
;
921 if (x
!= kidRect
.x
) {
922 kidFrame
->InvalidateOverflowRect();
925 desiredSize
.width
= cellDesiredSize
.width
;
926 desiredSize
.height
= cellDesiredSize
.height
;
927 if (cellFrame
->HasOverflowRect())
928 desiredSize
.mOverflowArea
= cellFrame
->GetOverflowRect();
930 desiredSize
.mOverflowArea
.SetRect(0, 0, cellDesiredSize
.width
,
931 cellDesiredSize
.height
);
933 // if we are in a floated table, our position is not yet established, so we cannot reposition our views
934 // the containing block will do this for us after positioning the table
935 if (!aTableFrame
.GetStyleDisplay()->IsFloating()) {
936 // Because we may have moved the frame we need to make sure any views are
937 // positioned properly. We have to do this, because any one of our parent
938 // frames could have moved and we have no way of knowing...
939 nsTableFrame::RePositionViews(kidFrame
);
943 if (NS_UNCONSTRAINEDSIZE
== aReflowState
.availableHeight
) {
944 if (!GetPrevInFlow()) {
945 // Calculate the cell's actual height given its pass2 height. This
946 // function takes into account the specified height (in the style)
947 CalculateCellActualHeight(cellFrame
, desiredSize
.height
);
949 // height may have changed, adjust descent to absorb any excess difference
951 if (!kidFrame
->GetFirstChild(nsnull
)->GetFirstChild(nsnull
))
952 ascent
= desiredSize
.height
;
954 ascent
= ((nsTableCellFrame
*)kidFrame
)->GetCellBaseline();
955 nscoord descent
= desiredSize
.height
- ascent
;
956 UpdateHeight(desiredSize
.height
, ascent
, descent
, &aTableFrame
, cellFrame
);
959 cellMaxHeight
= NS_MAX(cellMaxHeight
, desiredSize
.height
);
960 PRInt32 rowSpan
= aTableFrame
.GetEffectiveRowSpan((nsTableCellFrame
&)*kidFrame
);
962 SetContentHeight(cellMaxHeight
);
967 desiredSize
.width
= availCellWidth
;
969 FinishReflowChild(kidFrame
, aPresContext
, nsnull
, desiredSize
, x
, 0, 0);
971 nsTableFrame::InvalidateFrame(kidFrame
, kidRect
, kidOverflowRect
,
974 x
+= desiredSize
.width
;
977 if (kidRect
.x
!= x
) {
978 // Invalidate the old position
979 kidFrame
->InvalidateOverflowRect();
980 // move to the new position
981 kidFrame
->SetPosition(nsPoint(x
, kidRect
.y
));
982 nsTableFrame::RePositionViews(kidFrame
);
983 // invalidate the new position
984 kidFrame
->InvalidateOverflowRect();
986 // we need to account for the cell's width even if it isn't reflowed
989 if (kidFrame
->GetNextInFlow()) {
990 aStatus
= NS_FRAME_NOT_COMPLETE
;
993 ConsiderChildOverflow(aDesiredSize
.mOverflowArea
, kidFrame
);
997 // just set our width to what was available. The table will calculate the width and not use our value.
998 aDesiredSize
.width
= aReflowState
.availableWidth
;
1000 if (aReflowState
.mFlags
.mSpecialHeightReflow
) {
1001 aDesiredSize
.height
= mRect
.height
;
1003 else if (NS_UNCONSTRAINEDSIZE
== aReflowState
.availableHeight
) {
1004 aDesiredSize
.height
= CalcHeight(aReflowState
);
1005 if (GetPrevInFlow()) {
1006 nscoord height
= CalcHeightFromUnpaginatedHeight(aPresContext
, *this);
1007 aDesiredSize
.height
= NS_MAX(aDesiredSize
.height
, height
);
1010 if (isPaginated
&& HasStyleHeight()) {
1011 // set the unpaginated height so next in flows can try to honor it
1012 SetHasUnpaginatedHeight(PR_TRUE
);
1013 SetUnpaginatedHeight(aPresContext
, aDesiredSize
.height
);
1015 if (isPaginated
&& HasUnpaginatedHeight()) {
1016 aDesiredSize
.height
= NS_MAX(aDesiredSize
.height
, GetUnpaginatedHeight(aPresContext
));
1020 else { // constrained height, paginated
1021 // Compute the height we should have from style (subtracting the
1022 // height from our prev-in-flows from the style height)
1023 nscoord styleHeight
= CalcHeightFromUnpaginatedHeight(aPresContext
, *this);
1024 if (styleHeight
> aReflowState
.availableHeight
) {
1025 styleHeight
= aReflowState
.availableHeight
;
1026 NS_FRAME_SET_INCOMPLETE(aStatus
);
1028 aDesiredSize
.height
= NS_MAX(cellMaxHeight
, styleHeight
);
1030 nsRect
rowRect(0, 0, aDesiredSize
.width
, aDesiredSize
.height
);
1031 aDesiredSize
.mOverflowArea
.UnionRect(aDesiredSize
.mOverflowArea
, rowRect
);
1032 FinishAndStoreOverflow(&aDesiredSize
);
1036 /** Layout the entire row.
1037 * This method stacks cells horizontally according to HTML 4.0 rules.
1040 nsTableRowFrame::Reflow(nsPresContext
* aPresContext
,
1041 nsHTMLReflowMetrics
& aDesiredSize
,
1042 const nsHTMLReflowState
& aReflowState
,
1043 nsReflowStatus
& aStatus
)
1045 DO_GLOBAL_REFLOW_COUNT("nsTableRowFrame");
1046 DISPLAY_REFLOW(aPresContext
, this, aReflowState
, aDesiredSize
, aStatus
);
1047 nsresult rv
= NS_OK
;
1049 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
1051 return NS_ERROR_NULL_POINTER
;
1053 const nsStyleVisibility
* rowVis
= GetStyleVisibility();
1054 PRBool collapseRow
= (NS_STYLE_VISIBILITY_COLLAPSE
== rowVis
->mVisible
);
1056 tableFrame
->SetNeedToCollapse(PR_TRUE
);
1059 // see if a special height reflow needs to occur due to having a pct height
1060 nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState
);
1062 // See if we have a cell with specified/pct height
1063 InitHasCellWithStyleHeight(tableFrame
);
1065 rv
= ReflowChildren(aPresContext
, aDesiredSize
, aReflowState
, *tableFrame
,
1068 // just set our width to what was available. The table will calculate the width and not use our value.
1069 aDesiredSize
.width
= aReflowState
.availableWidth
;
1071 // If our parent is in initial reflow, it'll handle invalidating our
1072 // entire overflow rect.
1073 if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW
)) {
1074 CheckInvalidateSizeChange(aDesiredSize
);
1077 NS_FRAME_SET_TRUNCATION(aStatus
, aReflowState
, aDesiredSize
);
1082 * This function is called by the row group frame's SplitRowGroup() code when
1083 * pushing a row frame that has cell frames that span into it. The cell frame
1084 * should be reflowed with the specified height
1087 nsTableRowFrame::ReflowCellFrame(nsPresContext
* aPresContext
,
1088 const nsHTMLReflowState
& aReflowState
,
1089 PRBool aIsTopOfPage
,
1090 nsTableCellFrame
* aCellFrame
,
1091 nscoord aAvailableHeight
,
1092 nsReflowStatus
& aStatus
)
1094 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
1096 ABORT1(NS_ERROR_NULL_POINTER
);
1098 // Reflow the cell frame with the specified height. Use the existing width
1099 nsRect cellRect
= aCellFrame
->GetRect();
1100 nsRect cellOverflowRect
= aCellFrame
->GetOverflowRect();
1102 nsSize
availSize(cellRect
.width
, aAvailableHeight
);
1103 PRBool borderCollapse
= ((nsTableFrame
*)tableFrame
->GetFirstInFlow())->IsBorderCollapse();
1104 nsTableCellReflowState
cellReflowState(aPresContext
, aReflowState
,
1105 aCellFrame
, availSize
, PR_FALSE
);
1106 InitChildReflowState(*aPresContext
, availSize
, borderCollapse
, cellReflowState
);
1107 cellReflowState
.mFlags
.mIsTopOfPage
= aIsTopOfPage
;
1109 nsHTMLReflowMetrics desiredSize
;
1111 ReflowChild(aCellFrame
, aPresContext
, desiredSize
, cellReflowState
,
1112 0, 0, NS_FRAME_NO_MOVE_FRAME
, aStatus
);
1113 PRBool fullyComplete
= NS_FRAME_IS_COMPLETE(aStatus
) && !NS_FRAME_IS_TRUNCATED(aStatus
);
1114 if (fullyComplete
) {
1115 desiredSize
.height
= aAvailableHeight
;
1117 aCellFrame
->SetSize(nsSize(cellRect
.width
, desiredSize
.height
));
1119 // Note: VerticallyAlignChild can affect the overflow rect.
1120 // XXX What happens if this cell has 'vertical-align: baseline' ?
1121 // XXX Why is it assumed that the cell's ascent hasn't changed ?
1122 if (fullyComplete
) {
1123 aCellFrame
->VerticallyAlignChild(mMaxCellAscent
);
1126 nsTableFrame::InvalidateFrame(aCellFrame
, cellRect
,
1128 (aCellFrame
->GetStateBits() &
1129 NS_FRAME_FIRST_REFLOW
) != 0);
1131 aCellFrame
->DidReflow(aPresContext
, nsnull
, NS_FRAME_REFLOW_FINISHED
);
1133 return desiredSize
.height
;
1137 nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset
,
1139 PRBool aCollapseGroup
,
1140 PRBool
& aDidCollapse
)
1142 const nsStyleVisibility
* rowVis
= GetStyleVisibility();
1143 PRBool collapseRow
= (NS_STYLE_VISIBILITY_COLLAPSE
== rowVis
->mVisible
);
1144 nsTableFrame
* tableFrame
= static_cast<nsTableFrame
*>(nsTableFrame::GetTableFrame(this)->GetFirstInFlow());
1148 tableFrame
->SetNeedToCollapse(PR_TRUE
);
1151 if (aRowOffset
!= 0) {
1152 // We're moving, so invalidate our old position
1153 InvalidateOverflowRect();
1156 nsRect rowRect
= GetRect();
1157 nsRect oldRect
= rowRect
;
1158 nsRect oldOverflowRect
= GetOverflowRect();
1160 rowRect
.y
-= aRowOffset
;
1161 rowRect
.width
= aWidth
;
1162 nsRect
overflowArea(0, 0, 0, 0);
1164 nscoord cellSpacingX
= tableFrame
->GetCellSpacingX();
1165 nscoord cellSpacingY
= tableFrame
->GetCellSpacingY();
1167 if (aCollapseGroup
|| collapseRow
) {
1168 nsTableCellFrame
* cellFrame
= GetFirstCell();
1169 aDidCollapse
= PR_TRUE
;
1170 shift
= rowRect
.height
+ cellSpacingY
;
1172 nsRect cRect
= cellFrame
->GetRect();
1173 // If aRowOffset != 0, there's no point in invalidating the cells, since
1174 // we've already invalidated our overflow area. Note that we _do_ still
1175 // need to invalidate if our row is not moving, because the cell might
1176 // span out of this row, so invalidating our row rect won't do enough.
1177 if (aRowOffset
== 0) {
1181 cellFrame
->SetRect(cRect
);
1182 cellFrame
= cellFrame
->GetNextCell();
1186 else { // row is not collapsed
1187 nsTableIterator
iter(*this);
1188 // remember the col index of the previous cell to handle rowspans into this
1190 PRInt32 firstPrevColIndex
= (iter
.IsLeftToRight()) ? -1 :
1191 tableFrame
->GetColCount();
1192 PRInt32 prevColIndex
= firstPrevColIndex
;
1193 nscoord x
= 0; // running total of children x offset
1195 PRInt32 colIncrement
= iter
.IsLeftToRight() ? 1 : -1;
1197 //nscoord x = cellSpacingX;
1199 nsIFrame
* kidFrame
= iter
.First();
1201 nsTableCellFrame
*cellFrame
= do_QueryFrame(kidFrame
);
1203 PRInt32 cellColIndex
;
1204 cellFrame
->GetColIndex(cellColIndex
);
1205 PRInt32 cellColSpan
= tableFrame
->GetEffectiveColSpan(*cellFrame
);
1207 // If the adjacent cell is in a prior row (because of a rowspan) add in
1209 if ((iter
.IsLeftToRight() && (prevColIndex
!= (cellColIndex
- 1))) ||
1210 (!iter
.IsLeftToRight() &&
1211 (prevColIndex
!= cellColIndex
+ cellColSpan
))) {
1212 x
+= GetSpaceBetween(prevColIndex
, cellColIndex
, cellColSpan
,
1213 *tableFrame
, cellSpacingX
, iter
.IsLeftToRight(),
1216 nsRect
cRect(x
, 0, 0, rowRect
.height
);
1218 // remember the rightmost (ltr) or leftmost (rtl) column this cell
1220 prevColIndex
= (iter
.IsLeftToRight()) ?
1221 cellColIndex
+ (cellColSpan
- 1) : cellColIndex
;
1222 PRInt32 startIndex
= (iter
.IsLeftToRight()) ?
1223 cellColIndex
: cellColIndex
+ (cellColSpan
- 1);
1224 PRInt32 actualColSpan
= cellColSpan
;
1225 PRBool isVisible
= PR_FALSE
;
1226 for (PRInt32 colX
= startIndex
; actualColSpan
> 0;
1227 colX
+= colIncrement
, actualColSpan
--) {
1229 nsTableColFrame
* colFrame
= tableFrame
->GetColFrame(colX
);
1230 const nsStyleVisibility
* colVis
= colFrame
->GetStyleVisibility();
1231 PRBool collapseCol
= (NS_STYLE_VISIBILITY_COLLAPSE
==
1233 nsIFrame
* cgFrame
= colFrame
->GetParent();
1234 const nsStyleVisibility
* groupVis
= cgFrame
->GetStyleVisibility();
1235 PRBool collapseGroup
= (NS_STYLE_VISIBILITY_COLLAPSE
==
1236 groupVis
->mVisible
);
1237 PRBool isCollapsed
= collapseCol
|| collapseGroup
;
1239 cRect
.width
+= tableFrame
->GetColumnWidth(colX
);
1240 isVisible
= PR_TRUE
;
1241 if ((actualColSpan
> 1)) {
1242 nsTableColFrame
* nextColFrame
=
1243 tableFrame
->GetColFrame(colX
+ colIncrement
);
1244 const nsStyleVisibility
* nextColVis
=
1245 nextColFrame
->GetStyleVisibility();
1246 if ( (NS_STYLE_VISIBILITY_COLLAPSE
!= nextColVis
->mVisible
) &&
1247 tableFrame
->ColumnHasCellSpacingBefore(colX
+ colIncrement
)) {
1248 cRect
.width
+= cellSpacingX
;
1256 PRInt32 actualRowSpan
= tableFrame
->GetEffectiveRowSpan(*cellFrame
);
1257 nsTableRowFrame
* rowFrame
= GetNextRow();
1258 for (actualRowSpan
--; actualRowSpan
> 0 && rowFrame
; actualRowSpan
--) {
1259 const nsStyleVisibility
* nextRowVis
= rowFrame
->GetStyleVisibility();
1260 PRBool collapseNextRow
= (NS_STYLE_VISIBILITY_COLLAPSE
==
1261 nextRowVis
->mVisible
);
1262 if (!collapseNextRow
) {
1263 nsRect nextRect
= rowFrame
->GetRect();
1264 cRect
.height
+= nextRect
.height
+ cellSpacingY
;
1266 rowFrame
= rowFrame
->GetNextRow();
1269 nsRect oldCellRect
= cellFrame
->GetRect();
1270 nsRect oldCellOverflowRect
= cellFrame
->GetOverflowRect();
1272 if (aRowOffset
== 0 && cRect
.TopLeft() != oldCellRect
.TopLeft()) {
1273 // We're moving the cell. Invalidate the old overflow area
1274 cellFrame
->InvalidateOverflowRect();
1277 cellFrame
->SetRect(cRect
);
1279 // XXXbz This looks completely bogus in the cases when we didn't
1280 // collapse the cell!
1281 nsRect cellOverflow
= nsRect(0, 0, cRect
.width
, cRect
.height
);
1282 cellFrame
->FinishAndStoreOverflow(&cellOverflow
, nsSize(cRect
.width
,
1284 nsTableFrame::RePositionViews(cellFrame
);
1285 ConsiderChildOverflow(overflowArea
, cellFrame
);
1287 if (aRowOffset
== 0) {
1288 nsTableFrame::InvalidateFrame(cellFrame
, oldCellRect
,
1289 oldCellOverflowRect
, PR_FALSE
);
1292 kidFrame
= iter
.Next(); // Get the next child
1297 overflowArea
.UnionRect(nsRect(0,0,rowRect
.width
, rowRect
.height
),
1299 FinishAndStoreOverflow(&overflowArea
, nsSize(rowRect
.width
,
1302 nsTableFrame::RePositionViews(this);
1303 nsTableFrame::InvalidateFrame(this, oldRect
, oldOverflowRect
, PR_FALSE
);
1308 * The following method is called by the row group frame's SplitRowGroup()
1309 * when it creates a continuing cell frame and wants to insert it into the
1313 nsTableRowFrame::InsertCellFrame(nsTableCellFrame
* aFrame
,
1316 // Find the cell frame where col index < aColIndex
1317 nsTableCellFrame
* priorCell
= nsnull
;
1318 for (nsIFrame
* child
= mFrames
.FirstChild(); child
;
1319 child
= child
->GetNextSibling()) {
1320 nsTableCellFrame
*cellFrame
= do_QueryFrame(child
);
1323 cellFrame
->GetColIndex(colIndex
);
1324 if (colIndex
< aColIndex
) {
1325 priorCell
= cellFrame
;
1330 mFrames
.InsertFrame(this, priorCell
, aFrame
);
1334 nsTableRowFrame::GetType() const
1336 return nsGkAtoms::tableRowFrame
;
1340 nsTableRowFrame::GetNextRow() const
1342 nsIFrame
* childFrame
= GetNextSibling();
1343 while (childFrame
) {
1344 nsTableRowFrame
*rowFrame
= do_QueryFrame(childFrame
);
1346 NS_ASSERTION(NS_STYLE_DISPLAY_TABLE_ROW
== childFrame
->GetStyleDisplay()->mDisplay
, "wrong display type on rowframe");
1349 childFrame
= childFrame
->GetNextSibling();
1354 NS_DECLARE_FRAME_PROPERTY(RowUnpaginatedHeightProperty
, nsnull
)
1357 nsTableRowFrame::SetUnpaginatedHeight(nsPresContext
* aPresContext
,
1360 NS_ASSERTION(!GetPrevInFlow(), "program error");
1362 aPresContext
->PropertyTable()->
1363 Set(this, RowUnpaginatedHeightProperty(), NS_INT32_TO_PTR(aValue
));
1367 nsTableRowFrame::GetUnpaginatedHeight(nsPresContext
* aPresContext
)
1369 FrameProperties props
= GetFirstInFlow()->Properties();
1370 return NS_PTR_TO_INT32(props
.Get(RowUnpaginatedHeightProperty()));
1373 void nsTableRowFrame::SetContinuousBCBorderWidth(PRUint8 aForSide
,
1374 BCPixelSize aPixelValue
)
1378 mRightContBorderWidth
= aPixelValue
;
1381 mTopContBorderWidth
= aPixelValue
;
1384 mLeftContBorderWidth
= aPixelValue
;
1387 NS_ERROR("invalid NS_SIDE arg");
1392 * Sets the NS_ROW_HAS_CELL_WITH_STYLE_HEIGHT bit to indicate whether
1393 * this row has any cells that have non-auto-height. (Row-spanning
1394 * cells are ignored.)
1396 void nsTableRowFrame::InitHasCellWithStyleHeight(nsTableFrame
* aTableFrame
)
1398 nsTableIterator
iter(*this);
1400 for (nsIFrame
* kidFrame
= iter
.First(); kidFrame
; kidFrame
= iter
.Next()) {
1401 nsTableCellFrame
*cellFrame
= do_QueryFrame(kidFrame
);
1403 NS_NOTREACHED("Table row has a non-cell child.");
1406 // Ignore row-spanning cells
1407 if (aTableFrame
->GetEffectiveRowSpan(*cellFrame
) == 1 &&
1408 cellFrame
->GetStylePosition()->mHeight
.GetUnit() != eStyleUnit_Auto
) {
1409 AddStateBits(NS_ROW_HAS_CELL_WITH_STYLE_HEIGHT
);
1413 RemoveStateBits(NS_ROW_HAS_CELL_WITH_STYLE_HEIGHT
);
1416 /* ----- global methods ----- */
1419 NS_NewTableRowFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
1421 return new (aPresShell
) nsTableRowFrame(aContext
);
1424 NS_IMPL_FRAMEARENA_HELPERS(nsTableRowFrame
)
1428 nsTableRowFrame::GetFrameName(nsAString
& aResult
) const
1430 return MakeFrameName(NS_LITERAL_STRING("TableRow"), aResult
);