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.
23 * Mats Palmgren <mats.palmgren@bredband.net>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either of the GNU General Public License Version 2 or later (the "GPL"),
27 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include "nsTableRowGroupFrame.h"
40 #include "nsTableRowFrame.h"
41 #include "nsTableFrame.h"
42 #include "nsTableCellFrame.h"
43 #include "nsIRenderingContext.h"
44 #include "nsPresContext.h"
45 #include "nsStyleContext.h"
46 #include "nsStyleConsts.h"
47 #include "nsIContent.h"
48 #include "nsGkAtoms.h"
49 #include "nsIPresShell.h"
50 #include "nsCSSRendering.h"
51 #include "nsHTMLParts.h"
52 #include "nsCSSFrameConstructor.h"
53 #include "nsDisplayList.h"
55 #include "nsCellMap.h"//table cell navigation
57 nsTableRowGroupFrame::nsTableRowGroupFrame(nsStyleContext
* aContext
):
58 nsHTMLContainerFrame(aContext
)
60 SetRepeatable(PR_FALSE
);
63 nsTableRowGroupFrame::~nsTableRowGroupFrame()
68 nsTableRowGroupFrame::QueryInterface(const nsIID
& aIID
, void** aInstancePtr
)
70 NS_PRECONDITION(aInstancePtr
, "null out param");
72 static NS_DEFINE_IID(kITableRowGroupIID
, NS_ITABLEROWGROUPFRAME_IID
);
73 if (aIID
.Equals(kITableRowGroupIID
)) {
74 *aInstancePtr
= (void*)this;
78 return nsHTMLContainerFrame::QueryInterface(aIID
, aInstancePtr
);
82 nsTableRowGroupFrame::IsContainingBlock() const
88 nsTableRowGroupFrame::GetRowCount()
90 PRInt32 count
= 0; // init return
92 // loop through children, adding one to aCount for every legit row
93 nsIFrame
* childFrame
= GetFirstFrame();
97 if (NS_STYLE_DISPLAY_TABLE_ROW
== childFrame
->GetStyleDisplay()->mDisplay
)
99 GetNextFrame(childFrame
, &childFrame
);
104 PRInt32
nsTableRowGroupFrame::GetStartRowIndex()
107 nsIFrame
* childFrame
= GetFirstFrame();
111 if (NS_STYLE_DISPLAY_TABLE_ROW
== childFrame
->GetStyleDisplay()->mDisplay
) {
112 result
= ((nsTableRowFrame
*)childFrame
)->GetRowIndex();
115 GetNextFrame(childFrame
, &childFrame
);
117 // if the row group doesn't have any children, get it the hard way
119 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
121 return tableFrame
->GetStartRowIndex(*this);
128 void nsTableRowGroupFrame::AdjustRowIndices(PRInt32 aRowIndex
,
129 PRInt32 anAdjustment
)
131 nsIFrame
* rowFrame
= GetFirstChild(nsnull
);
132 for ( ; rowFrame
; rowFrame
= rowFrame
->GetNextSibling()) {
133 if (NS_STYLE_DISPLAY_TABLE_ROW
==rowFrame
->GetStyleDisplay()->mDisplay
) {
134 PRInt32 index
= ((nsTableRowFrame
*)rowFrame
)->GetRowIndex();
135 if (index
>= aRowIndex
)
136 ((nsTableRowFrame
*)rowFrame
)->SetRowIndex(index
+anAdjustment
);
141 nsTableRowGroupFrame::InitRepeatedFrame(nsPresContext
* aPresContext
,
142 nsTableRowGroupFrame
* aHeaderFooterFrame
)
144 nsTableRowFrame
* copyRowFrame
= GetFirstRow();
145 nsTableRowFrame
* originalRowFrame
= aHeaderFooterFrame
->GetFirstRow();
146 AddStateBits(NS_REPEATED_ROW_OR_ROWGROUP
);
147 while (copyRowFrame
&& originalRowFrame
) {
148 copyRowFrame
->AddStateBits(NS_REPEATED_ROW_OR_ROWGROUP
);
149 int rowIndex
= originalRowFrame
->GetRowIndex();
150 copyRowFrame
->SetRowIndex(rowIndex
);
152 // For each table cell frame set its column index
153 nsTableCellFrame
* originalCellFrame
= originalRowFrame
->GetFirstCell();
154 nsTableCellFrame
* copyCellFrame
= copyRowFrame
->GetFirstCell();
155 while (copyCellFrame
&& originalCellFrame
) {
156 NS_ASSERTION(originalCellFrame
->GetContent() == copyCellFrame
->GetContent(),
157 "cell frames have different content");
159 originalCellFrame
->GetColIndex(colIndex
);
160 copyCellFrame
->SetColIndex(colIndex
);
162 // Move to the next cell frame
163 copyCellFrame
= copyCellFrame
->GetNextCell();
164 originalCellFrame
= originalCellFrame
->GetNextCell();
167 // Move to the next row frame
168 originalRowFrame
= originalRowFrame
->GetNextRow();
169 copyRowFrame
= copyRowFrame
->GetNextRow();
176 * We need a custom display item for table row backgrounds. This is only used
177 * when the table row is the root of a stacking context (e.g., has 'opacity').
178 * Table row backgrounds can extend beyond the row frame bounds, when
179 * the row contains row-spanning cells.
181 class nsDisplayTableRowGroupBackground
: public nsDisplayTableItem
{
183 nsDisplayTableRowGroupBackground(nsTableRowGroupFrame
* aFrame
) : nsDisplayTableItem(aFrame
) {
184 MOZ_COUNT_CTOR(nsDisplayTableRowGroupBackground
);
186 #ifdef NS_BUILD_REFCNT_LOGGING
187 virtual ~nsDisplayTableRowGroupBackground() {
188 MOZ_COUNT_DTOR(nsDisplayTableRowGroupBackground
);
192 virtual void Paint(nsDisplayListBuilder
* aBuilder
, nsIRenderingContext
* aCtx
,
193 const nsRect
& aDirtyRect
);
195 NS_DISPLAY_DECL_NAME("TableRowGroupBackground")
199 nsDisplayTableRowGroupBackground::Paint(nsDisplayListBuilder
* aBuilder
,
200 nsIRenderingContext
* aCtx
, const nsRect
& aDirtyRect
) {
201 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(mFrame
);
203 nsPoint pt
= aBuilder
->ToReferenceFrame(mFrame
);
204 TableBackgroundPainter
painter(tableFrame
,
205 TableBackgroundPainter::eOrigin_TableRowGroup
,
206 mFrame
->PresContext(), *aCtx
,
208 painter
.PaintRowGroup(static_cast<nsTableRowGroupFrame
*>(mFrame
));
211 // Handle the child-traversal part of DisplayGenericTablePart
213 DisplayRows(nsDisplayListBuilder
* aBuilder
, nsFrame
* aFrame
,
214 const nsRect
& aDirtyRect
, const nsDisplayListSet
& aLists
)
216 nscoord overflowAbove
;
217 nsTableRowGroupFrame
* f
= static_cast<nsTableRowGroupFrame
*>(aFrame
);
218 // Don't try to use the row cursor if we have to descend into placeholders;
219 // we might have rows containing placeholders, where the row's overflow
220 // area doesn't intersect the dirty rect but we need to descend into the row
221 // to see out of flows
222 nsIFrame
* kid
= f
->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO
223 ? nsnull
: f
->GetFirstRowContaining(aDirtyRect
.y
, &overflowAbove
);
226 // have a cursor, use it
228 if (kid
->GetRect().y
- overflowAbove
>= aDirtyRect
.YMost())
230 nsresult rv
= f
->BuildDisplayListForChild(aBuilder
, kid
, aDirtyRect
, aLists
);
231 NS_ENSURE_SUCCESS(rv
, rv
);
232 kid
= kid
->GetNextSibling();
237 // No cursor. Traverse children the hard way and build a cursor while we're at it
238 nsTableRowGroupFrame::FrameCursorData
* cursor
= f
->SetupRowCursor();
239 kid
= f
->GetFirstChild(nsnull
);
241 nsresult rv
= f
->BuildDisplayListForChild(aBuilder
, kid
, aDirtyRect
, aLists
);
248 if (!cursor
->AppendFrame(kid
)) {
250 return NS_ERROR_OUT_OF_MEMORY
;
254 kid
= kid
->GetNextSibling();
257 cursor
->FinishBuildingCursor();
264 nsTableRowGroupFrame::BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
265 const nsRect
& aDirtyRect
,
266 const nsDisplayListSet
& aLists
)
268 if (!IsVisibleInSelection(aBuilder
))
271 PRBool isRoot
= aBuilder
->IsAtRootOfPseudoStackingContext() || IsScrolled();
272 nsDisplayTableItem
* item
= nsnull
;
274 // This background is created regardless of whether this frame is
275 // visible or not. Visibility decisions are delegated to the
276 // table background painter.
277 item
= new (aBuilder
) nsDisplayTableRowGroupBackground(this);
278 nsresult rv
= aLists
.BorderBackground()->AppendNewToTop(item
);
279 NS_ENSURE_SUCCESS(rv
, rv
);
282 return nsTableFrame::DisplayGenericTablePart(aBuilder
, this, aDirtyRect
,
283 aLists
, item
, DisplayRows
);
287 nsTableRowGroupFrame::GetSkipSides() const
290 if (nsnull
!= GetPrevInFlow()) {
291 skip
|= 1 << NS_SIDE_TOP
;
293 if (nsnull
!= GetNextInFlow()) {
294 skip
|= 1 << NS_SIDE_BOTTOM
;
299 // Position and size aKidFrame and update our reflow state. The origin of
300 // aKidRect is relative to the upper-left origin of our frame
302 nsTableRowGroupFrame::PlaceChild(nsPresContext
* aPresContext
,
303 nsRowGroupReflowState
& aReflowState
,
305 nsHTMLReflowMetrics
& aDesiredSize
,
306 const nsRect
& aOriginalKidRect
,
307 const nsRect
& aOriginalKidOverflowRect
)
309 PRBool isFirstReflow
=
310 (aKidFrame
->GetStateBits() & NS_FRAME_FIRST_REFLOW
) != 0;
312 // Place and size the child
313 FinishReflowChild(aKidFrame
, aPresContext
, nsnull
, aDesiredSize
, 0,
316 nsTableFrame::InvalidateFrame(aKidFrame
, aOriginalKidRect
,
317 aOriginalKidOverflowRect
, isFirstReflow
);
319 // Adjust the running y-offset
320 aReflowState
.y
+= aDesiredSize
.height
;
322 // If our height is constrained then update the available height
323 if (NS_UNCONSTRAINEDSIZE
!= aReflowState
.availSize
.height
) {
324 aReflowState
.availSize
.height
-= aDesiredSize
.height
;
329 nsTableRowGroupFrame::InitChildReflowState(nsPresContext
& aPresContext
,
330 PRBool aBorderCollapse
,
331 nsHTMLReflowState
& aReflowState
)
333 nsMargin collapseBorder
;
334 nsMargin
padding(0,0,0,0);
335 nsMargin
* pCollapseBorder
= nsnull
;
336 if (aBorderCollapse
) {
337 if (aReflowState
.frame
) {
338 if (nsGkAtoms::tableRowFrame
== aReflowState
.frame
->GetType()) {
339 nsTableRowFrame
* rowFrame
= (nsTableRowFrame
*)aReflowState
.frame
;
340 pCollapseBorder
= rowFrame
->GetBCBorderWidth(collapseBorder
);
344 aReflowState
.Init(&aPresContext
, -1, -1, pCollapseBorder
, &padding
);
348 CacheRowHeightsForPrinting(nsPresContext
* aPresContext
,
349 nsTableRowFrame
* aFirstRow
)
351 for (nsTableRowFrame
* row
= aFirstRow
; row
; row
= row
->GetNextRow()) {
352 if (!row
->GetPrevInFlow()) {
353 row
->SetHasUnpaginatedHeight(PR_TRUE
);
354 row
->SetUnpaginatedHeight(aPresContext
, row
->GetSize().height
);
360 nsTableRowGroupFrame::ReflowChildren(nsPresContext
* aPresContext
,
361 nsHTMLReflowMetrics
& aDesiredSize
,
362 nsRowGroupReflowState
& aReflowState
,
363 nsReflowStatus
& aStatus
,
364 PRBool
* aPageBreakBeforeEnd
)
366 if (aPageBreakBeforeEnd
)
367 *aPageBreakBeforeEnd
= PR_FALSE
;
369 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
371 ABORT1(NS_ERROR_NULL_POINTER
);
375 PRBool borderCollapse
= tableFrame
->IsBorderCollapse();
377 nscoord cellSpacingY
= tableFrame
->GetCellSpacingY();
379 // XXXldb Should we really be checking this rather than available height?
380 // (Think about multi-column layout!)
381 PRBool isPaginated
= aPresContext
->IsPaginated();
383 PRBool haveRow
= PR_FALSE
;
384 PRBool reflowAllKids
= aReflowState
.reflowState
.ShouldReflowAllKids() ||
385 tableFrame
->IsGeometryDirty();
386 PRBool needToCalcRowHeights
= reflowAllKids
;
388 nsIFrame
*prevKidFrame
= nsnull
;
389 for (nsIFrame
* kidFrame
= GetFirstFrame(); kidFrame
;
390 prevKidFrame
= kidFrame
, kidFrame
= kidFrame
->GetNextSibling()) {
391 if (kidFrame
->GetType() != nsGkAtoms::tableRowFrame
) {
392 // XXXldb nsCSSFrameConstructor needs to enforce this!
393 NS_NOTREACHED("yikes, a non-row child");
399 // Reflow the row frame
401 NS_SUBTREE_DIRTY(kidFrame
) ||
402 (aReflowState
.reflowState
.mFlags
.mSpecialHeightReflow
&&
403 (isPaginated
|| (kidFrame
->GetStateBits() &
404 NS_FRAME_CONTAINS_RELATIVE_HEIGHT
)))) {
405 nsRect oldKidRect
= kidFrame
->GetRect();
406 nsRect oldKidOverflowRect
= kidFrame
->GetOverflowRect();
408 // XXXldb We used to only pass aDesiredSize.mFlags through for the
409 // incremental reflow codepath.
410 nsHTMLReflowMetrics
desiredSize(aDesiredSize
.mFlags
);
411 desiredSize
.width
= desiredSize
.height
= 0;
413 // Reflow the child into the available space, giving it as much height as
414 // it wants. We'll deal with splitting later after we've computed the row
415 // heights, taking into account cells with row spans...
416 nsSize
kidAvailSize(aReflowState
.availSize
.width
, NS_UNCONSTRAINEDSIZE
);
417 nsHTMLReflowState
kidReflowState(aPresContext
, aReflowState
.reflowState
,
418 kidFrame
, kidAvailSize
,
420 InitChildReflowState(*aPresContext
, borderCollapse
, kidReflowState
);
422 // This can indicate that columns were resized.
423 if (aReflowState
.reflowState
.mFlags
.mHResize
)
424 kidReflowState
.mFlags
.mHResize
= PR_TRUE
;
426 NS_ASSERTION(kidFrame
== GetFirstFrame() || prevKidFrame
,
427 "If we're not on the first frame, we should have a "
428 "previous sibling...");
429 // If prev row has nonzero YMost, then we can't be at the top of the page
430 if (prevKidFrame
&& prevKidFrame
->GetRect().YMost() > 0) {
431 kidReflowState
.mFlags
.mIsTopOfPage
= PR_FALSE
;
434 rv
= ReflowChild(kidFrame
, aPresContext
, desiredSize
, kidReflowState
,
435 0, aReflowState
.y
, NS_FRAME_INVALIDATE_ON_MOVE
,
439 PlaceChild(aPresContext
, aReflowState
, kidFrame
, desiredSize
,
440 oldKidRect
, oldKidOverflowRect
);
441 aReflowState
.y
+= cellSpacingY
;
443 if (!reflowAllKids
) {
444 if (IsSimpleRowFrame(aReflowState
.tableFrame
, kidFrame
)) {
445 // Inform the row of its new height.
446 ((nsTableRowFrame
*)kidFrame
)->DidResize();
447 // the overflow area may have changed inflate the overflow area
448 const nsStylePosition
*stylePos
= GetStylePosition();
449 nsStyleUnit unit
= stylePos
->mHeight
.GetUnit();
450 if (aReflowState
.tableFrame
->IsAutoHeight() &&
451 unit
!= eStyleUnit_Coord
) {
452 // Because other cells in the row may need to be aligned
453 // differently, repaint the entire row
454 nsRect
kidRect(0, aReflowState
.y
,
455 desiredSize
.width
, desiredSize
.height
);
458 // Invalidate the area we're offseting. Note that we only
459 // repaint within our existing frame bounds.
460 if (kidRect
.YMost() < mRect
.height
) {
461 nsRect
dirtyRect(0, kidRect
.YMost(),
462 mRect
.width
, mRect
.height
- kidRect
.YMost());
463 Invalidate(dirtyRect
);
466 else if (oldKidRect
.height
!= desiredSize
.height
)
467 needToCalcRowHeights
= PR_TRUE
;
469 needToCalcRowHeights
= PR_TRUE
;
473 if (isPaginated
&& aPageBreakBeforeEnd
&& !*aPageBreakBeforeEnd
) {
474 nsTableRowFrame
* nextRow
= ((nsTableRowFrame
*)kidFrame
)->GetNextRow();
476 *aPageBreakBeforeEnd
= nsTableFrame::PageBreakAfter(*kidFrame
, nextRow
);
480 SlideChild(aReflowState
, kidFrame
);
482 // Adjust the running y-offset so we know where the next row should be placed
483 nscoord height
= kidFrame
->GetSize().height
+ cellSpacingY
;
484 aReflowState
.y
+= height
;
486 if (NS_UNCONSTRAINEDSIZE
!= aReflowState
.availSize
.height
) {
487 aReflowState
.availSize
.height
-= height
;
490 ConsiderChildOverflow(aDesiredSize
.mOverflowArea
, kidFrame
);
494 aReflowState
.y
-= cellSpacingY
;
496 // Return our desired rect
497 aDesiredSize
.width
= aReflowState
.reflowState
.availableWidth
;
498 aDesiredSize
.height
= aReflowState
.y
;
500 if (aReflowState
.reflowState
.mFlags
.mSpecialHeightReflow
) {
501 DidResizeRows(aDesiredSize
);
503 CacheRowHeightsForPrinting(aPresContext
, GetFirstRow());
506 else if (needToCalcRowHeights
) {
507 CalculateRowHeights(aPresContext
, aDesiredSize
, aReflowState
.reflowState
);
508 if (!reflowAllKids
) {
509 // Because we don't know what changed repaint everything.
510 // XXX We should change CalculateRowHeights() to return the bounding
511 // rect of what changed. Or whether anything moved or changed size...
512 nsRect
dirtyRect(0, 0, mRect
.width
, mRect
.height
);
513 Invalidate(dirtyRect
);
521 nsTableRowGroupFrame::GetFirstRow()
523 for (nsIFrame
* childFrame
= GetFirstFrame(); childFrame
;
524 childFrame
= childFrame
->GetNextSibling()) {
525 if (nsGkAtoms::tableRowFrame
== childFrame
->GetType()) {
526 return (nsTableRowFrame
*)childFrame
;
534 RowInfo() { height
= pctHeight
= hasStyleHeight
= hasPctHeight
= isSpecial
= 0; }
535 unsigned height
; // content height or fixed height, excluding pct height
536 unsigned pctHeight
:29; // pct height
537 unsigned hasStyleHeight
:1;
538 unsigned hasPctHeight
:1;
539 unsigned isSpecial
:1; // there is no cell originating in the row with rowspan=1 and there are at
540 // least 2 cells spanning the row and there is no style height on the row
544 UpdateHeights(RowInfo
& aRowInfo
,
545 nscoord aAdditionalHeight
,
547 nscoord
& aUnconstrainedTotal
)
549 aRowInfo
.height
+= aAdditionalHeight
;
550 aTotal
+= aAdditionalHeight
;
551 if (!aRowInfo
.hasStyleHeight
) {
552 aUnconstrainedTotal
+= aAdditionalHeight
;
557 nsTableRowGroupFrame::DidResizeRows(nsHTMLReflowMetrics
& aDesiredSize
)
559 // update the cells spanning rows with their new heights
560 // this is the place where all of the cells in the row get set to the height of the row
561 // Reset the overflow area
562 aDesiredSize
.mOverflowArea
= nsRect(0, 0, 0, 0);
563 for (nsTableRowFrame
* rowFrame
= GetFirstRow();
564 rowFrame
; rowFrame
= rowFrame
->GetNextRow()) {
565 rowFrame
->DidResize();
566 ConsiderChildOverflow(aDesiredSize
.mOverflowArea
, rowFrame
);
570 // This calculates the height of all the rows and takes into account
571 // style height on the row group, style heights on rows and cells, style heights on rowspans.
572 // Actual row heights will be adjusted later if the table has a style height.
573 // Even if rows don't change height, this method must be called to set the heights of each
574 // cell in the row to the height of its row.
576 nsTableRowGroupFrame::CalculateRowHeights(nsPresContext
* aPresContext
,
577 nsHTMLReflowMetrics
& aDesiredSize
,
578 const nsHTMLReflowState
& aReflowState
)
580 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
581 if (!tableFrame
) return;
583 PRBool isPaginated
= aPresContext
->IsPaginated();
585 // all table cells have the same top and bottom margins, namely cellSpacingY
586 nscoord cellSpacingY
= tableFrame
->GetCellSpacingY();
588 PRInt32 numEffCols
= tableFrame
->GetEffectiveColCount();
590 PRInt32 startRowIndex
= GetStartRowIndex();
591 // find the row corresponding to the row index we just found
592 nsTableRowFrame
* startRowFrame
= GetFirstRow();
594 if (!startRowFrame
) return;
596 // the current row group height is the y origin of the 1st row we are about to calculated a height for
597 nscoord startRowGroupHeight
= startRowFrame
->GetPosition().y
;
599 PRInt32 numRows
= GetRowCount() - (startRowFrame
->GetRowIndex() - GetStartRowIndex());
600 // collect the current height of each row. nscoord* rowHeights = nsnull;
604 nsTArray
<RowInfo
> rowInfo
;
605 if (!rowInfo
.AppendElements(numRows
)) {
609 PRBool hasRowSpanningCell
= PR_FALSE
;
610 nscoord heightOfRows
= 0;
611 nscoord heightOfUnStyledRows
= 0;
612 // Get the height of each row without considering rowspans. This will be the max of
613 // the largest desired height of each cell, the largest style height of each cell,
614 // the style height of the row.
615 nscoord pctHeightBasis
= GetHeightBasis(aReflowState
);
616 PRInt32 rowIndex
; // the index in rowInfo, not among the rows in the row group
617 nsTableRowFrame
* rowFrame
;
618 for (rowFrame
= startRowFrame
, rowIndex
= 0; rowFrame
; rowFrame
= rowFrame
->GetNextRow(), rowIndex
++) {
619 nscoord nonPctHeight
= rowFrame
->GetContentHeight();
621 nonPctHeight
= PR_MAX(nonPctHeight
, rowFrame
->GetSize().height
);
623 if (!rowFrame
->GetPrevInFlow()) {
624 if (rowFrame
->HasPctHeight()) {
625 rowInfo
[rowIndex
].hasPctHeight
= PR_TRUE
;
626 rowInfo
[rowIndex
].pctHeight
= rowFrame
->GetHeight(pctHeightBasis
);
628 rowInfo
[rowIndex
].hasStyleHeight
= rowFrame
->HasStyleHeight();
629 nonPctHeight
= PR_MAX(nonPctHeight
, rowFrame
->GetFixedHeight());
631 UpdateHeights(rowInfo
[rowIndex
], nonPctHeight
, heightOfRows
, heightOfUnStyledRows
);
633 if (!rowInfo
[rowIndex
].hasStyleHeight
) {
634 if (isPaginated
|| tableFrame
->HasMoreThanOneCell(rowIndex
+ startRowIndex
)) {
635 rowInfo
[rowIndex
].isSpecial
= PR_TRUE
;
636 // iteratate the row's cell frames to see if any do not have rowspan > 1
637 nsTableCellFrame
* cellFrame
= rowFrame
->GetFirstCell();
639 PRInt32 rowSpan
= tableFrame
->GetEffectiveRowSpan(rowIndex
+ startRowIndex
, *cellFrame
);
641 rowInfo
[rowIndex
].isSpecial
= PR_FALSE
;
644 cellFrame
= cellFrame
->GetNextCell();
648 // See if a cell spans into the row. If so we'll have to do the next step
649 if (!hasRowSpanningCell
) {
650 if (tableFrame
->RowIsSpannedInto(rowIndex
+ startRowIndex
, numEffCols
)) {
651 hasRowSpanningCell
= PR_TRUE
;
656 if (hasRowSpanningCell
) {
657 // Get the height of cells with rowspans and allocate any extra space to the rows they span
658 // iteratate the child frames and process the row frames among them
659 for (rowFrame
= startRowFrame
, rowIndex
= 0; rowFrame
; rowFrame
= rowFrame
->GetNextRow(), rowIndex
++) {
660 // See if the row has an originating cell with rowspan > 1. We cannot determine this for a row in a
661 // continued row group by calling RowHasSpanningCells, because the row's fif may not have any originating
662 // cells yet the row may have a continued cell which originates in it.
663 if (GetPrevInFlow() || tableFrame
->RowHasSpanningCells(startRowIndex
+ rowIndex
, numEffCols
)) {
664 nsTableCellFrame
* cellFrame
= rowFrame
->GetFirstCell();
665 // iteratate the row's cell frames
667 PRInt32 rowSpan
= tableFrame
->GetEffectiveRowSpan(rowIndex
+ startRowIndex
, *cellFrame
);
668 if ((rowIndex
+ rowSpan
) > numRows
) {
669 // there might be rows pushed already to the nextInFlow
670 rowSpan
= numRows
- rowIndex
;
672 if (rowSpan
> 1) { // a cell with rowspan > 1, determine the height of the rows it spans
673 nscoord heightOfRowsSpanned
= 0;
674 nscoord heightOfUnStyledRowsSpanned
= 0;
675 nscoord numSpecialRowsSpanned
= 0;
676 nscoord cellSpacingTotal
= 0;
678 for (spanX
= 0; spanX
< rowSpan
; spanX
++) {
679 heightOfRowsSpanned
+= rowInfo
[rowIndex
+ spanX
].height
;
680 if (!rowInfo
[rowIndex
+ spanX
].hasStyleHeight
) {
681 heightOfUnStyledRowsSpanned
+= rowInfo
[rowIndex
+ spanX
].height
;
684 cellSpacingTotal
+= cellSpacingY
;
686 if (rowInfo
[rowIndex
+ spanX
].isSpecial
) {
687 numSpecialRowsSpanned
++;
690 nscoord heightOfAreaSpanned
= heightOfRowsSpanned
+ cellSpacingTotal
;
691 // get the height of the cell
692 nsSize cellFrameSize
= cellFrame
->GetSize();
693 nsSize cellDesSize
= cellFrame
->GetDesiredSize();
694 rowFrame
->CalculateCellActualSize(cellFrame
, cellDesSize
.width
,
695 cellDesSize
.height
, cellDesSize
.width
);
696 cellFrameSize
.height
= cellDesSize
.height
;
697 if (cellFrame
->HasVerticalAlignBaseline()) {
698 // to ensure that a spanning cell with a long descender doesn't
699 // collide with the next row, we need to take into account the shift
700 // that will be done to align the cell on the baseline of the row.
701 cellFrameSize
.height
+= rowFrame
->GetMaxCellAscent() -
702 cellFrame
->GetCellBaseline();
705 if (heightOfAreaSpanned
< cellFrameSize
.height
) {
706 // the cell's height is larger than the available space of the rows it
707 // spans so distribute the excess height to the rows affected
708 nscoord extra
= cellFrameSize
.height
- heightOfAreaSpanned
;
709 nscoord extraUsed
= 0;
710 if (0 == numSpecialRowsSpanned
) {
711 //NS_ASSERTION(heightOfRowsSpanned > 0, "invalid row span situation");
712 PRBool haveUnStyledRowsSpanned
= (heightOfUnStyledRowsSpanned
> 0);
713 nscoord divisor
= (haveUnStyledRowsSpanned
)
714 ? heightOfUnStyledRowsSpanned
: heightOfRowsSpanned
;
716 for (spanX
= rowSpan
- 1; spanX
>= 0; spanX
--) {
717 if (!haveUnStyledRowsSpanned
|| !rowInfo
[rowIndex
+ spanX
].hasStyleHeight
) {
718 // The amount of additional space each row gets is proportional to its height
719 float percent
= ((float)rowInfo
[rowIndex
+ spanX
].height
) / ((float)divisor
);
721 // give rows their percentage, except for the first row which gets the remainder
722 nscoord extraForRow
= (0 == spanX
) ? extra
- extraUsed
723 : NSToCoordRound(((float)(extra
)) * percent
);
724 extraForRow
= PR_MIN(extraForRow
, extra
- extraUsed
);
725 // update the row height
726 UpdateHeights(rowInfo
[rowIndex
+ spanX
], extraForRow
, heightOfRows
, heightOfUnStyledRows
);
727 extraUsed
+= extraForRow
;
728 if (extraUsed
>= extra
) {
729 NS_ASSERTION((extraUsed
== extra
), "invalid row height calculation");
736 // put everything in the last row
737 UpdateHeights(rowInfo
[rowIndex
+ rowSpan
- 1], extra
, heightOfRows
, heightOfUnStyledRows
);
741 // give the extra to the special rows
742 nscoord numSpecialRowsAllocated
= 0;
743 for (spanX
= rowSpan
- 1; spanX
>= 0; spanX
--) {
744 if (rowInfo
[rowIndex
+ spanX
].isSpecial
) {
745 // The amount of additional space each degenerate row gets is proportional to the number of them
746 float percent
= 1.0f
/ ((float)numSpecialRowsSpanned
);
748 // give rows their percentage, except for the first row which gets the remainder
749 nscoord extraForRow
= (numSpecialRowsSpanned
- 1 == numSpecialRowsAllocated
)
751 : NSToCoordRound(((float)(extra
)) * percent
);
752 extraForRow
= PR_MIN(extraForRow
, extra
- extraUsed
);
753 // update the row height
754 UpdateHeights(rowInfo
[rowIndex
+ spanX
], extraForRow
, heightOfRows
, heightOfUnStyledRows
);
755 extraUsed
+= extraForRow
;
756 if (extraUsed
>= extra
) {
757 NS_ASSERTION((extraUsed
== extra
), "invalid row height calculation");
764 } // if (rowSpan > 1)
765 cellFrame
= cellFrame
->GetNextCell();
766 } // while (cellFrame)
767 } // if (tableFrame->RowHasSpanningCells(startRowIndex + rowIndex) {
768 } // while (rowFrame)
771 // pct height rows have already got their content heights. Give them their pct heights up to pctHeightBasis
772 nscoord extra
= pctHeightBasis
- heightOfRows
;
773 for (rowFrame
= startRowFrame
, rowIndex
= 0; rowFrame
&& (extra
> 0); rowFrame
= rowFrame
->GetNextRow(), rowIndex
++) {
774 RowInfo
& rInfo
= rowInfo
[rowIndex
];
775 if (rInfo
.hasPctHeight
) {
776 nscoord rowExtra
= (rInfo
.pctHeight
> rInfo
.height
)
777 ? rInfo
.pctHeight
- rInfo
.height
: 0;
778 rowExtra
= PR_MIN(rowExtra
, extra
);
779 UpdateHeights(rInfo
, rowExtra
, heightOfRows
, heightOfUnStyledRows
);
784 PRBool styleHeightAllocation
= PR_FALSE
;
785 nscoord rowGroupHeight
= startRowGroupHeight
+ heightOfRows
+ ((numRows
- 1) * cellSpacingY
);
786 // if we have a style height, allocate the extra height to unconstrained rows
787 if ((aReflowState
.ComputedHeight() > rowGroupHeight
) &&
788 (NS_UNCONSTRAINEDSIZE
!= aReflowState
.ComputedHeight())) {
789 nscoord extraComputedHeight
= aReflowState
.ComputedHeight() - rowGroupHeight
;
790 nscoord extraUsed
= 0;
791 PRBool haveUnStyledRows
= (heightOfUnStyledRows
> 0);
792 nscoord divisor
= (haveUnStyledRows
)
793 ? heightOfUnStyledRows
: heightOfRows
;
795 styleHeightAllocation
= PR_TRUE
;
796 for (rowIndex
= 0; rowIndex
< numRows
; rowIndex
++) {
797 if (!haveUnStyledRows
|| !rowInfo
[rowIndex
].hasStyleHeight
) {
798 // The amount of additional space each row gets is based on the
799 // percentage of space it occupies
800 float percent
= ((float)rowInfo
[rowIndex
].height
) / ((float)divisor
);
801 // give rows their percentage, except for the last row which gets the remainder
802 nscoord extraForRow
= (numRows
- 1 == rowIndex
)
803 ? extraComputedHeight
- extraUsed
804 : NSToCoordRound(((float)extraComputedHeight
) * percent
);
805 extraForRow
= PR_MIN(extraForRow
, extraComputedHeight
- extraUsed
);
806 // update the row height
807 UpdateHeights(rowInfo
[rowIndex
], extraForRow
, heightOfRows
, heightOfUnStyledRows
);
808 extraUsed
+= extraForRow
;
809 if (extraUsed
>= extraComputedHeight
) {
810 NS_ASSERTION((extraUsed
== extraComputedHeight
), "invalid row height calculation");
816 rowGroupHeight
= aReflowState
.ComputedHeight();
819 nscoord yOrigin
= startRowGroupHeight
;
820 // update the rows with their (potentially) new heights
821 for (rowFrame
= startRowFrame
, rowIndex
= 0; rowFrame
; rowFrame
= rowFrame
->GetNextRow(), rowIndex
++) {
822 nsRect rowBounds
= rowFrame
->GetRect();
823 nsRect rowOverflowRect
= rowFrame
->GetOverflowRect();
825 PRBool movedFrame
= (rowBounds
.y
!= yOrigin
);
826 nscoord rowHeight
= (rowInfo
[rowIndex
].height
> 0) ? rowInfo
[rowIndex
].height
: 0;
828 if (movedFrame
|| (rowHeight
!= rowBounds
.height
)) {
829 // Resize/move the row to its final size and position
831 rowFrame
->InvalidateOverflowRect();
834 rowFrame
->SetRect(nsRect(rowBounds
.x
, yOrigin
, rowBounds
.width
,
837 nsTableFrame::InvalidateFrame(rowFrame
, rowBounds
, rowOverflowRect
,
841 nsTableFrame::RePositionViews(rowFrame
);
842 // XXXbz we don't need to update our overflow area?
844 yOrigin
+= rowHeight
+ cellSpacingY
;
847 if (isPaginated
&& styleHeightAllocation
) {
848 // since the row group has a style height, cache the row heights, so next in flows can honor them
849 CacheRowHeightsForPrinting(aPresContext
, GetFirstRow());
852 DidResizeRows(aDesiredSize
);
854 aDesiredSize
.height
= rowGroupHeight
; // Adjust our desired size
858 nsTableRowGroupFrame::CollapseRowGroupIfNecessary(nscoord aYTotalOffset
,
861 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
863 const nsStyleVisibility
* groupVis
= GetStyleVisibility();
864 PRBool collapseGroup
= (NS_STYLE_VISIBILITY_COLLAPSE
== groupVis
->mVisible
);
866 tableFrame
->SetNeedToCollapse(PR_TRUE
);
869 nsRect
overflowArea(0, 0, 0, 0);
871 nsTableRowFrame
* rowFrame
= GetFirstRow();
872 PRBool didCollapse
= PR_FALSE
;
873 nscoord yGroupOffset
= 0;
875 yGroupOffset
+= rowFrame
->CollapseRowIfNecessary(yGroupOffset
,
876 aWidth
, collapseGroup
,
878 ConsiderChildOverflow(overflowArea
, rowFrame
);
879 rowFrame
= rowFrame
->GetNextRow();
882 nsRect groupRect
= GetRect();
883 nsRect oldGroupRect
= groupRect
;
884 nsRect oldGroupOverflowRect
= GetOverflowRect();
886 groupRect
.height
-= yGroupOffset
;
888 // add back the cellspacing between rowgroups
889 groupRect
.height
+= tableFrame
->GetCellSpacingY();
892 groupRect
.y
-= aYTotalOffset
;
893 groupRect
.width
= aWidth
;
895 if (aYTotalOffset
!= 0) {
896 InvalidateOverflowRect();
900 overflowArea
.UnionRect(nsRect(0, 0, groupRect
.width
, groupRect
.height
),
902 FinishAndStoreOverflow(&overflowArea
, nsSize(groupRect
.width
,
904 nsTableFrame::RePositionViews(this);
905 nsTableFrame::InvalidateFrame(this, oldGroupRect
, oldGroupOverflowRect
,
911 // Move a child that was skipped during a reflow.
913 nsTableRowGroupFrame::SlideChild(nsRowGroupReflowState
& aReflowState
,
916 // Move the frame if we need to
917 nsPoint oldPosition
= aKidFrame
->GetPosition();
918 nsPoint newPosition
= oldPosition
;
919 newPosition
.y
= aReflowState
.y
;
920 if (oldPosition
.y
!= newPosition
.y
) {
921 aKidFrame
->InvalidateOverflowRect();
922 aKidFrame
->SetPosition(newPosition
);
923 nsTableFrame::RePositionViews(aKidFrame
);
924 aKidFrame
->InvalidateOverflowRect();
928 // Create a continuing frame, add it to the child list, and then push it
929 // and the frames that follow
931 nsTableRowGroupFrame::CreateContinuingRowFrame(nsPresContext
& aPresContext
,
933 nsIFrame
** aContRowFrame
)
935 // XXX what is the row index?
936 if (!aContRowFrame
) {NS_ASSERTION(PR_FALSE
, "bad call"); return;}
937 // create the continuing frame which will create continuing cell frames
938 nsresult rv
= aPresContext
.PresShell()->FrameConstructor()->
939 CreateContinuingFrame(&aPresContext
, &aRowFrame
, this, aContRowFrame
);
941 *aContRowFrame
= nsnull
;
945 // Add the continuing row frame to the child list
947 GetNextFrame(&aRowFrame
, &nextRow
);
948 (*aContRowFrame
)->SetNextSibling(nextRow
);
949 aRowFrame
.SetNextSibling(*aContRowFrame
);
951 // Push the continuing row frame and the frames that follow
952 PushChildren(&aPresContext
, *aContRowFrame
, &aRowFrame
);
955 // Reflow the cells with rowspan > 1 which originate between aFirstRow
956 // and end on or after aLastRow. aFirstTruncatedRow is the highest row on the
957 // page that contains a cell which cannot split on this page
959 nsTableRowGroupFrame::SplitSpanningCells(nsPresContext
& aPresContext
,
960 const nsHTMLReflowState
& aReflowState
,
961 nsTableFrame
& aTable
,
962 nsTableRowFrame
& aFirstRow
,
963 nsTableRowFrame
& aLastRow
,
964 PRBool aFirstRowIsTopOfPage
,
965 nscoord aSpanningRowBottom
,
966 nsTableRowFrame
*& aContRow
,
967 nsTableRowFrame
*& aFirstTruncatedRow
,
968 nscoord
& aDesiredHeight
)
970 NS_ASSERTION(aSpanningRowBottom
>= 0, "Can't split negative heights");
971 aFirstTruncatedRow
= nsnull
;
974 PRInt32 lastRowIndex
= aLastRow
.GetRowIndex();
975 PRBool wasLast
= PR_FALSE
;
976 // Iterate the rows between aFirstRow and aLastRow
977 for (nsTableRowFrame
* row
= &aFirstRow
; !wasLast
; row
= row
->GetNextRow()) {
978 wasLast
= (row
== &aLastRow
);
979 PRInt32 rowIndex
= row
->GetRowIndex();
980 nsPoint rowPos
= row
->GetPosition();
981 // Iterate the cells looking for those that have rowspan > 1
982 for (nsTableCellFrame
* cell
= row
->GetFirstCell(); cell
; cell
= cell
->GetNextCell()) {
983 PRInt32 rowSpan
= aTable
.GetEffectiveRowSpan(rowIndex
, *cell
);
984 // Only reflow rowspan > 1 cells which span aLastRow. Those which don't span aLastRow
985 // were reflowed correctly during the unconstrained height reflow.
986 if ((rowSpan
> 1) && (rowIndex
+ rowSpan
> lastRowIndex
)) {
987 nsReflowStatus status
;
988 // Ask the row to reflow the cell to the height of all the rows it spans up through aLastRow
989 // aAvailHeight is the space between the row group start and the end of the page
990 nscoord cellAvailHeight
= aSpanningRowBottom
- rowPos
.y
;
991 NS_ASSERTION(cellAvailHeight
>= 0, "No space for cell?");
992 PRBool isTopOfPage
= (row
== &aFirstRow
) && aFirstRowIsTopOfPage
;
993 nscoord cellHeight
= row
->ReflowCellFrame(&aPresContext
, aReflowState
,
995 cellAvailHeight
, status
);
996 aDesiredHeight
= PR_MAX(aDesiredHeight
, rowPos
.y
+ cellHeight
);
997 if (NS_FRAME_IS_COMPLETE(status
)) {
998 if (cellHeight
> cellAvailHeight
) {
999 aFirstTruncatedRow
= row
;
1000 if ((row
!= &aFirstRow
) || !aFirstRowIsTopOfPage
) {
1001 // return now, since we will be getting another reflow after either (1) row is
1002 // moved to the next page or (2) the row group is moved to the next page
1009 CreateContinuingRowFrame(aPresContext
, aLastRow
, (nsIFrame
**)&aContRow
);
1012 if (row
!= &aLastRow
) {
1013 // aContRow needs a continuation for cell, since cell spanned into aLastRow
1014 // but does not originate there
1015 nsTableCellFrame
* contCell
= nsnull
;
1016 aPresContext
.PresShell()->FrameConstructor()->
1017 CreateContinuingFrame(&aPresContext
, cell
, &aLastRow
,
1018 (nsIFrame
**)&contCell
);
1020 cell
->GetColIndex(colIndex
);
1021 aContRow
->InsertCellFrame(contCell
, colIndex
);
1030 // Remove the next-in-flow of the row, its cells and their cell blocks. This
1031 // is necessary in case the row doesn't need a continuation later on or needs
1032 // a continuation which doesn't have the same number of cells that now exist.
1034 nsTableRowGroupFrame::UndoContinuedRow(nsPresContext
* aPresContext
,
1035 nsTableRowFrame
* aRow
)
1037 if (!aRow
) return; // allow null aRow to avoid callers doing null checks
1039 // rowBefore was the prev-sibling of aRow's next-sibling before aRow was created
1040 nsTableRowFrame
* rowBefore
= (nsTableRowFrame
*)aRow
->GetPrevInFlow();
1042 nsIFrame
* firstOverflow
= GetOverflowFrames(aPresContext
, PR_TRUE
);
1043 if (!rowBefore
|| !firstOverflow
|| (firstOverflow
!= aRow
)) {
1044 NS_ASSERTION(PR_FALSE
, "invalid continued row");
1048 // Remove aRow from the sibling chain and hook its next-sibling up with rowBefore
1049 rowBefore
->SetNextSibling(aRow
->GetNextSibling());
1051 // Destroy the row, its cells, and their cell blocks. Cell blocks that have split
1052 // will not have reflowed yet to pick up content from any overflow lines.
1056 static nsTableRowFrame
*
1057 GetRowBefore(nsTableRowFrame
& aStartRow
,
1058 nsTableRowFrame
& aRow
)
1060 nsTableRowFrame
* rowBefore
= nsnull
;
1061 for (nsTableRowFrame
* sib
= &aStartRow
; sib
&& (sib
!= &aRow
); sib
= sib
->GetNextRow()) {
1068 nsTableRowGroupFrame::SplitRowGroup(nsPresContext
* aPresContext
,
1069 nsHTMLReflowMetrics
& aDesiredSize
,
1070 const nsHTMLReflowState
& aReflowState
,
1071 nsTableFrame
* aTableFrame
,
1072 nsReflowStatus
& aStatus
)
1074 NS_PRECONDITION(aPresContext
->IsPaginated(), "SplitRowGroup currently supports only paged media");
1076 nsresult rv
= NS_OK
;
1077 nsTableRowFrame
* prevRowFrame
= nsnull
;
1078 aDesiredSize
.height
= 0;
1080 nscoord availWidth
= aReflowState
.availableWidth
;
1081 nscoord availHeight
= aReflowState
.availableHeight
;
1083 PRBool borderCollapse
= ((nsTableFrame
*)aTableFrame
->GetFirstInFlow())->IsBorderCollapse();
1084 nscoord cellSpacingY
= aTableFrame
->GetCellSpacingY();
1086 // get the page height
1087 nscoord pageHeight
= aPresContext
->GetPageSize().height
;
1088 NS_ASSERTION(pageHeight
!= NS_UNCONSTRAINEDSIZE
,
1089 "The table shouldn't be split when there should be space");
1091 PRBool isTopOfPage
= aReflowState
.mFlags
.mIsTopOfPage
;
1092 nsTableRowFrame
* firstRowThisPage
= GetFirstRow();
1094 // Need to dirty the table's geometry, or else the row might skip
1095 // reflowing its cell as an optimization.
1096 aTableFrame
->SetGeometryDirty();
1098 // Walk each of the row frames looking for the first row frame that doesn't fit
1099 // in the available space
1100 for (nsTableRowFrame
* rowFrame
= firstRowThisPage
; rowFrame
; rowFrame
= rowFrame
->GetNextRow()) {
1101 PRBool rowIsOnPage
= PR_TRUE
;
1102 nsRect rowRect
= rowFrame
->GetRect();
1103 // See if the row fits on this page
1104 if (rowRect
.YMost() > availHeight
) {
1105 nsTableRowFrame
* contRow
= nsnull
;
1106 // Reflow the row in the availabe space and have it split if it is the 1st
1107 // row (on the page) or there is at least 5% of the current page available
1108 // XXX this 5% should be made a preference
1109 if (!prevRowFrame
|| (availHeight
- aDesiredSize
.height
> pageHeight
/ 20)) {
1110 nsSize
availSize(availWidth
, PR_MAX(availHeight
- rowRect
.y
, 0));
1111 // don't let the available height exceed what CalculateRowHeights set for it
1112 availSize
.height
= PR_MIN(availSize
.height
, rowRect
.height
);
1114 nsHTMLReflowState
rowReflowState(aPresContext
, aReflowState
,
1115 rowFrame
, availSize
,
1118 InitChildReflowState(*aPresContext
, borderCollapse
, rowReflowState
);
1119 rowReflowState
.mFlags
.mIsTopOfPage
= isTopOfPage
; // set top of page
1120 nsHTMLReflowMetrics rowMetrics
;
1122 // Get the old size before we reflow.
1123 nsRect oldRowRect
= rowFrame
->GetRect();
1124 nsRect oldRowOverflowRect
= rowFrame
->GetOverflowRect();
1126 // Reflow the cell with the constrained height. A cell with rowspan >1 will get this
1127 // reflow later during SplitSpanningCells.
1128 rv
= ReflowChild(rowFrame
, aPresContext
, rowMetrics
, rowReflowState
,
1129 0, 0, NS_FRAME_NO_MOVE_FRAME
, aStatus
);
1130 if (NS_FAILED(rv
)) return rv
;
1131 rowFrame
->SetSize(nsSize(rowMetrics
.width
, rowMetrics
.height
));
1132 rowFrame
->DidReflow(aPresContext
, nsnull
, NS_FRAME_REFLOW_FINISHED
);
1133 rowFrame
->DidResize();
1135 nsTableFrame::InvalidateFrame(rowFrame
, oldRowRect
, oldRowOverflowRect
,
1138 if (NS_FRAME_IS_NOT_COMPLETE(aStatus
)) {
1139 // The row frame is incomplete and all of the rowspan 1 cells' block frames split
1140 if ((rowMetrics
.height
<= rowReflowState
.availableHeight
) || isTopOfPage
) {
1141 // The row stays on this page because either it split ok or we're on the top of page.
1142 // If top of page and the height exceeded the avail height, then there will be data loss
1143 NS_ASSERTION(rowMetrics
.height
<= rowReflowState
.availableHeight
,
1144 "data loss - incomplete row needed more height than available, on top of page");
1145 CreateContinuingRowFrame(*aPresContext
, *rowFrame
, (nsIFrame
**)&contRow
);
1147 aDesiredSize
.height
+= rowMetrics
.height
;
1149 aDesiredSize
.height
+= cellSpacingY
;
1151 else return NS_ERROR_NULL_POINTER
;
1154 // Put the row on the next page to give it more height
1155 rowIsOnPage
= PR_FALSE
;
1159 // The row frame is complete because either (1) its minimum height is greater than the
1160 // available height we gave it, or (2) it may have been given a larger height through
1161 // style than its content, or (3) it contains a rowspan >1 cell which hasn't been
1162 // reflowed with a constrained height yet (we will find out when SplitSpanningCells is
1164 if (rowMetrics
.height
> availSize
.height
) {
1165 // cases (1) and (2)
1167 // We're on top of the page, so keep the row on this page. There will be data loss.
1168 // Push the row frame that follows
1169 nsTableRowFrame
* nextRowFrame
= rowFrame
->GetNextRow();
1171 aStatus
= NS_FRAME_NOT_COMPLETE
;
1173 aDesiredSize
.height
+= rowMetrics
.height
;
1175 aDesiredSize
.height
+= cellSpacingY
;
1176 NS_WARNING("data loss - complete row needed more height than available, on top of page");
1179 // We're not on top of the page, so put the row on the next page to give it more height
1180 rowIsOnPage
= PR_FALSE
;
1184 } //if (!prevRowFrame || (availHeight - aDesiredSize.height > pageHeight / 20))
1186 // put the row on the next page to give it more height
1187 rowIsOnPage
= PR_FALSE
;
1190 nsTableRowFrame
* lastRowThisPage
= rowFrame
;
1191 nscoord spanningRowBottom
= availHeight
;
1193 NS_ASSERTION(!contRow
, "We should not have created a continuation if none of this row fits");
1195 spanningRowBottom
= prevRowFrame
->GetRect().YMost();
1196 lastRowThisPage
= prevRowFrame
;
1197 isTopOfPage
= (lastRowThisPage
== firstRowThisPage
) && aReflowState
.mFlags
.mIsTopOfPage
;
1198 aStatus
= NS_FRAME_NOT_COMPLETE
;
1201 // We can't push children, so let our parent reflow us again with more space
1202 aDesiredSize
.height
= rowRect
.YMost();
1203 aStatus
= NS_FRAME_COMPLETE
;
1207 // reflow the cells with rowspan >1 that occur on the page
1209 nsTableRowFrame
* firstTruncatedRow
;
1211 SplitSpanningCells(*aPresContext
, aReflowState
, *aTableFrame
, *firstRowThisPage
,
1212 *lastRowThisPage
, aReflowState
.mFlags
.mIsTopOfPage
, spanningRowBottom
, contRow
,
1213 firstTruncatedRow
, yMost
);
1214 if (firstTruncatedRow
) {
1215 // A rowspan >1 cell did not fit (and could not split) in the space we gave it
1216 if (firstTruncatedRow
== firstRowThisPage
) {
1217 if (aReflowState
.mFlags
.mIsTopOfPage
) {
1218 NS_WARNING("data loss in a row spanned cell");
1221 // We can't push children, so let our parent reflow us again with more space
1222 aDesiredSize
.height
= rowRect
.YMost();
1223 aStatus
= NS_FRAME_COMPLETE
;
1224 UndoContinuedRow(aPresContext
, contRow
);
1228 else { // (firstTruncatedRow != firstRowThisPage)
1229 // Try to put firstTruncateRow on the next page
1230 nsTableRowFrame
* rowBefore
= ::GetRowBefore(*firstRowThisPage
, *firstTruncatedRow
);
1231 nscoord oldSpanningRowBottom
= spanningRowBottom
;
1232 spanningRowBottom
= rowBefore
->GetRect().YMost();
1234 UndoContinuedRow(aPresContext
, contRow
);
1236 nsTableRowFrame
* oldLastRowThisPage
= lastRowThisPage
;
1237 lastRowThisPage
= firstTruncatedRow
;
1238 aStatus
= NS_FRAME_NOT_COMPLETE
;
1240 // Call SplitSpanningCells again with rowBefore as the last row on the page
1241 SplitSpanningCells(*aPresContext
, aReflowState
, *aTableFrame
,
1242 *firstRowThisPage
, *rowBefore
, aReflowState
.mFlags
.mIsTopOfPage
,
1243 spanningRowBottom
, contRow
, firstTruncatedRow
, aDesiredSize
.height
);
1244 if (firstTruncatedRow
) {
1245 if (aReflowState
.mFlags
.mIsTopOfPage
) {
1246 // We were better off with the 1st call to SplitSpanningCells, do it again
1247 UndoContinuedRow(aPresContext
, contRow
);
1249 lastRowThisPage
= oldLastRowThisPage
;
1250 spanningRowBottom
= oldSpanningRowBottom
;
1251 SplitSpanningCells(*aPresContext
, aReflowState
, *aTableFrame
, *firstRowThisPage
,
1252 *lastRowThisPage
, aReflowState
.mFlags
.mIsTopOfPage
, spanningRowBottom
, contRow
,
1253 firstTruncatedRow
, aDesiredSize
.height
);
1254 NS_WARNING("data loss in a row spanned cell");
1257 // Let our parent reflow us again with more space
1258 aDesiredSize
.height
= rowRect
.YMost();
1259 aStatus
= NS_FRAME_COMPLETE
;
1260 UndoContinuedRow(aPresContext
, contRow
);
1264 } // if (firstTruncatedRow == firstRowThisPage)
1265 } // if (firstTruncatedRow)
1267 aDesiredSize
.height
= PR_MAX(aDesiredSize
.height
, yMost
);
1269 aStatus
= NS_FRAME_NOT_COMPLETE
;
1272 if (NS_FRAME_IS_NOT_COMPLETE(aStatus
) && !contRow
) {
1273 nsTableRowFrame
* nextRow
= lastRowThisPage
->GetNextRow();
1275 PushChildren(aPresContext
, nextRow
, lastRowThisPage
);
1279 } // if (rowRect.YMost() > availHeight)
1281 aDesiredSize
.height
= rowRect
.YMost();
1282 prevRowFrame
= rowFrame
;
1283 // see if there is a page break after the row
1284 nsTableRowFrame
* nextRow
= rowFrame
->GetNextRow();
1285 if (nextRow
&& nsTableFrame::PageBreakAfter(*rowFrame
, nextRow
)) {
1286 PushChildren(aPresContext
, nextRow
, rowFrame
);
1287 aStatus
= NS_FRAME_NOT_COMPLETE
;
1291 // after the 1st row that has a height, we can't be on top
1292 // of the page anymore.
1293 isTopOfPage
= isTopOfPage
&& rowRect
.YMost() == 0;
1298 /** Layout the entire row group.
1299 * This method stacks rows vertically according to HTML 4.0 rules.
1300 * Rows are responsible for layout of their children.
1303 nsTableRowGroupFrame::Reflow(nsPresContext
* aPresContext
,
1304 nsHTMLReflowMetrics
& aDesiredSize
,
1305 const nsHTMLReflowState
& aReflowState
,
1306 nsReflowStatus
& aStatus
)
1308 DO_GLOBAL_REFLOW_COUNT("nsTableRowGroupFrame");
1309 DISPLAY_REFLOW(aPresContext
, this, aReflowState
, aDesiredSize
, aStatus
);
1311 nsresult rv
= NS_OK
;
1312 aStatus
= NS_FRAME_COMPLETE
;
1314 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
1315 if (!tableFrame
) return NS_ERROR_NULL_POINTER
;
1317 // Row geometry may be going to change so we need to invalidate any row cursor.
1320 // see if a special height reflow needs to occur due to having a pct height
1321 nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState
);
1323 nsRowGroupReflowState
state(aReflowState
, tableFrame
);
1324 const nsStyleVisibility
* groupVis
= GetStyleVisibility();
1325 PRBool collapseGroup
= (NS_STYLE_VISIBILITY_COLLAPSE
== groupVis
->mVisible
);
1326 if (collapseGroup
) {
1327 tableFrame
->SetNeedToCollapse(PR_TRUE
);
1330 // Check for an overflow list
1331 MoveOverflowToChildList(aPresContext
);
1333 // Reflow the existing frames.
1334 PRBool splitDueToPageBreak
= PR_FALSE
;
1335 rv
= ReflowChildren(aPresContext
, aDesiredSize
, state
, aStatus
,
1336 &splitDueToPageBreak
);
1338 // See if all the frames fit. Do not try to split anything if we're
1339 // not paginated ... we can't split across columns yet.
1340 if (aReflowState
.mFlags
.mTableIsSplittable
&&
1341 (NS_FRAME_NOT_COMPLETE
== aStatus
|| splitDueToPageBreak
||
1342 (NS_UNCONSTRAINEDSIZE
!= aReflowState
.availableHeight
&&
1343 aDesiredSize
.height
> aReflowState
.availableHeight
))) {
1344 // Nope, find a place to split the row group
1345 PRBool specialReflow
= (PRBool
)aReflowState
.mFlags
.mSpecialHeightReflow
;
1346 ((nsHTMLReflowState::ReflowStateFlags
&)aReflowState
.mFlags
).mSpecialHeightReflow
= PR_FALSE
;
1348 SplitRowGroup(aPresContext
, aDesiredSize
, aReflowState
, tableFrame
, aStatus
);
1350 ((nsHTMLReflowState::ReflowStateFlags
&)aReflowState
.mFlags
).mSpecialHeightReflow
= specialReflow
;
1353 // If we have a next-in-flow, then we're not complete
1354 // XXXldb This used to be done only for the incremental reflow codepath.
1355 if (GetNextInFlow()) {
1356 aStatus
= NS_FRAME_NOT_COMPLETE
;
1359 SetHasStyleHeight((NS_UNCONSTRAINEDSIZE
!= aReflowState
.ComputedHeight()) &&
1360 (aReflowState
.ComputedHeight() > 0));
1362 // just set our width to what was available. The table will calculate the width and not use our value.
1363 aDesiredSize
.width
= aReflowState
.availableWidth
;
1365 aDesiredSize
.mOverflowArea
.UnionRect(aDesiredSize
.mOverflowArea
, nsRect(0, 0, aDesiredSize
.width
,
1366 aDesiredSize
.height
));
1368 // If our parent is in initial reflow, it'll handle invalidating our
1369 // entire overflow rect.
1370 if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW
)) {
1371 CheckInvalidateSizeChange(aDesiredSize
);
1374 FinishAndStoreOverflow(&aDesiredSize
);
1375 NS_FRAME_SET_TRUNCATION(aStatus
, aReflowState
, aDesiredSize
);
1380 nsTableRowGroupFrame::DidSetStyleContext(nsStyleContext
* aOldStyleContext
)
1382 if (!aOldStyleContext
) //avoid this on init
1385 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
1387 if (tableFrame
->IsBorderCollapse() &&
1388 tableFrame
->BCRecalcNeeded(aOldStyleContext
, GetStyleContext())) {
1389 nsRect
damageArea(0, GetStartRowIndex(), tableFrame
->GetColCount(),
1391 tableFrame
->SetBCDamageArea(damageArea
);
1397 nsTableRowGroupFrame::AppendFrames(nsIAtom
* aListName
,
1398 nsIFrame
* aFrameList
)
1400 NS_ASSERTION(!aListName
, "unexpected child list");
1404 // collect the new row frames in an array
1405 nsAutoVoidArray rows
;
1406 for (nsIFrame
* rowFrame
= aFrameList
; rowFrame
;
1407 rowFrame
= rowFrame
->GetNextSibling()) {
1408 if (nsGkAtoms::tableRowFrame
== rowFrame
->GetType()) {
1409 NS_ASSERTION(NS_STYLE_DISPLAY_TABLE_ROW
==
1410 rowFrame
->GetStyleDisplay()->mDisplay
,
1411 "wrong display type on rowframe");
1412 rows
.AppendElement(rowFrame
);
1416 PRInt32 rowIndex
= GetRowCount();
1417 // Append the frames to the sibling chain
1418 mFrames
.AppendFrames(nsnull
, aFrameList
);
1420 if (rows
.Count() > 0) {
1421 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
1423 tableFrame
->AppendRows(*this, rowIndex
, rows
);
1424 PresContext()->PresShell()->
1425 FrameNeedsReflow(this, nsIPresShell::eTreeChange
,
1426 NS_FRAME_HAS_DIRTY_CHILDREN
);
1427 tableFrame
->SetGeometryDirty();
1435 nsTableRowGroupFrame::InsertFrames(nsIAtom
* aListName
,
1436 nsIFrame
* aPrevFrame
,
1437 nsIFrame
* aFrameList
)
1439 NS_ASSERTION(!aListName
, "unexpected child list");
1440 NS_ASSERTION(!aPrevFrame
|| aPrevFrame
->GetParent() == this,
1441 "inserting after sibling frame with different parent");
1445 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
1447 return NS_ERROR_NULL_POINTER
;
1449 // collect the new row frames in an array
1451 PRBool gotFirstRow
= PR_FALSE
;
1452 for (nsIFrame
* rowFrame
= aFrameList
; rowFrame
;
1453 rowFrame
= rowFrame
->GetNextSibling()) {
1454 if (nsGkAtoms::tableRowFrame
== rowFrame
->GetType()) {
1455 NS_ASSERTION(NS_STYLE_DISPLAY_TABLE_ROW
==
1456 rowFrame
->GetStyleDisplay()->mDisplay
,
1457 "wrong display type on rowframe");
1458 rows
.AppendElement(rowFrame
);
1460 ((nsTableRowFrame
*)rowFrame
)->SetFirstInserted(PR_TRUE
);
1461 gotFirstRow
= PR_TRUE
;
1462 tableFrame
->SetRowInserted(PR_TRUE
);
1467 PRInt32 startRowIndex
= GetStartRowIndex();
1468 // Insert the frames in the sibling chain
1469 mFrames
.InsertFrames(nsnull
, aPrevFrame
, aFrameList
);
1471 PRInt32 numRows
= rows
.Count();
1473 nsTableRowFrame
* prevRow
= (nsTableRowFrame
*)nsTableFrame::GetFrameAtOrBefore(this, aPrevFrame
, nsGkAtoms::tableRowFrame
);
1474 PRInt32 rowIndex
= (prevRow
) ? prevRow
->GetRowIndex() + 1 : startRowIndex
;
1475 tableFrame
->InsertRows(*this, rows
, rowIndex
, PR_TRUE
);
1477 PresContext()->PresShell()->
1478 FrameNeedsReflow(this, nsIPresShell::eTreeChange
,
1479 NS_FRAME_HAS_DIRTY_CHILDREN
);
1480 tableFrame
->SetGeometryDirty();
1486 nsTableRowGroupFrame::RemoveFrame(nsIAtom
* aListName
,
1487 nsIFrame
* aOldFrame
)
1489 NS_ASSERTION(!aListName
, "unexpected child list");
1493 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
1495 if (nsGkAtoms::tableRowFrame
== aOldFrame
->GetType()) {
1496 // remove the rows from the table (and flag a rebalance)
1497 tableFrame
->RemoveRows((nsTableRowFrame
&)*aOldFrame
, 1, PR_TRUE
);
1499 PresContext()->PresShell()->
1500 FrameNeedsReflow(this, nsIPresShell::eTreeChange
,
1501 NS_FRAME_HAS_DIRTY_CHILDREN
);
1502 tableFrame
->SetGeometryDirty();
1505 mFrames
.DestroyFrame(aOldFrame
);
1510 /* virtual */ nsMargin
1511 nsTableRowGroupFrame::GetUsedMargin() const
1513 return nsMargin(0,0,0,0);
1516 /* virtual */ nsMargin
1517 nsTableRowGroupFrame::GetUsedBorder() const
1519 return nsMargin(0,0,0,0);
1522 /* virtual */ nsMargin
1523 nsTableRowGroupFrame::GetUsedPadding() const
1525 return nsMargin(0,0,0,0);
1529 nsTableRowGroupFrame::GetHeightBasis(const nsHTMLReflowState
& aReflowState
)
1532 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
1534 if ((aReflowState
.ComputedHeight() > 0) && (aReflowState
.ComputedHeight() < NS_UNCONSTRAINEDSIZE
)) {
1535 nscoord cellSpacing
= PR_MAX(0, GetRowCount() - 1) * tableFrame
->GetCellSpacingY();
1536 result
= aReflowState
.ComputedHeight() - cellSpacing
;
1539 const nsHTMLReflowState
* parentRS
= aReflowState
.parentReflowState
;
1540 if (parentRS
&& (tableFrame
!= parentRS
->frame
)) {
1541 parentRS
= parentRS
->parentReflowState
;
1543 if (parentRS
&& (tableFrame
== parentRS
->frame
) &&
1544 (parentRS
->ComputedHeight() > 0) && (parentRS
->ComputedHeight() < NS_UNCONSTRAINEDSIZE
)) {
1545 nscoord cellSpacing
= PR_MAX(0, tableFrame
->GetRowCount() + 1) * tableFrame
->GetCellSpacingY();
1546 result
= parentRS
->ComputedHeight() - cellSpacing
;
1555 nsTableRowGroupFrame::IsSimpleRowFrame(nsTableFrame
* aTableFrame
,
1558 // Make sure it's a row frame and not a row group frame
1559 if (aFrame
->GetType() == nsGkAtoms::tableRowFrame
) {
1560 PRInt32 rowIndex
= ((nsTableRowFrame
*)aFrame
)->GetRowIndex();
1562 // It's a simple row frame if there are no cells that span into or
1564 PRInt32 numEffCols
= aTableFrame
->GetEffectiveColCount();
1565 if (!aTableFrame
->RowIsSpannedInto(rowIndex
, numEffCols
) &&
1566 !aTableFrame
->RowHasSpanningCells(rowIndex
, numEffCols
)) {
1575 nsTableRowGroupFrame::GetType() const
1577 return nsGkAtoms::tableRowGroupFrame
;
1581 /* ----- global methods ----- */
1584 NS_NewTableRowGroupFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
1586 return new (aPresShell
) nsTableRowGroupFrame(aContext
);
1591 nsTableRowGroupFrame::GetFrameName(nsAString
& aResult
) const
1593 return MakeFrameName(NS_LITERAL_STRING("TableRowGroup"), aResult
);
1598 nsTableRowGroupFrame::GetBCBorderWidth(nsMargin
& aBorder
)
1600 aBorder
.left
= aBorder
.right
= aBorder
.top
= aBorder
.bottom
= 0;
1602 nsTableRowFrame
* firstRowFrame
= nsnull
;
1603 nsTableRowFrame
* lastRowFrame
= nsnull
;
1604 for (nsTableRowFrame
* rowFrame
= GetFirstRow(); rowFrame
; rowFrame
= rowFrame
->GetNextRow()) {
1605 if (!firstRowFrame
) {
1606 firstRowFrame
= rowFrame
;
1608 lastRowFrame
= rowFrame
;
1610 if (firstRowFrame
) {
1611 aBorder
.top
= nsPresContext::CSSPixelsToAppUnits(firstRowFrame
->GetTopBCBorderWidth());
1612 aBorder
.bottom
= nsPresContext::CSSPixelsToAppUnits(lastRowFrame
->GetBottomBCBorderWidth());
1618 void nsTableRowGroupFrame::SetContinuousBCBorderWidth(PRUint8 aForSide
,
1619 BCPixelSize aPixelValue
)
1623 mRightContBorderWidth
= aPixelValue
;
1625 case NS_SIDE_BOTTOM
:
1626 mBottomContBorderWidth
= aPixelValue
;
1629 mLeftContBorderWidth
= aPixelValue
;
1632 NS_ERROR("invalid NS_SIDE argument");
1636 //nsILineIterator methods
1638 nsTableRowGroupFrame::GetNumLines()
1640 return GetRowCount();
1644 nsTableRowGroupFrame::GetDirection()
1646 nsTableFrame
* table
= nsTableFrame::GetTableFrame(this);
1647 return (NS_STYLE_DIRECTION_RTL
==
1648 table
->GetStyleVisibility()->mDirection
);
1652 nsTableRowGroupFrame::GetLine(PRInt32 aLineNumber
,
1653 nsIFrame
** aFirstFrameOnLine
,
1654 PRInt32
* aNumFramesOnLine
,
1655 nsRect
& aLineBounds
,
1656 PRUint32
* aLineFlags
)
1658 NS_ENSURE_ARG_POINTER(aFirstFrameOnLine
);
1659 NS_ENSURE_ARG_POINTER(aNumFramesOnLine
);
1660 NS_ENSURE_ARG_POINTER(aLineFlags
);
1662 nsTableFrame
* table
= nsTableFrame::GetTableFrame(this);
1663 nsTableCellMap
* cellMap
= table
->GetCellMap();
1666 *aFirstFrameOnLine
= nsnull
;
1667 *aNumFramesOnLine
= 0;
1668 aLineBounds
.SetRect(0, 0, 0, 0);
1670 if ((aLineNumber
< 0) || (aLineNumber
>= GetRowCount())) {
1673 aLineNumber
+= GetStartRowIndex();
1675 *aNumFramesOnLine
= cellMap
->GetNumCellsOriginatingInRow(aLineNumber
);
1676 if (*aNumFramesOnLine
== 0) {
1679 PRInt32 colCount
= table
->GetColCount();
1680 for (PRInt32 i
= 0; i
< colCount
; i
++) {
1681 CellData
* data
= cellMap
->GetDataAt(aLineNumber
, i
);
1682 if (data
&& data
->IsOrig()) {
1683 *aFirstFrameOnLine
= (nsIFrame
*)data
->GetCellFrame();
1684 nsIFrame
* parent
= (*aFirstFrameOnLine
)->GetParent();
1685 aLineBounds
= parent
->GetRect();
1689 NS_ERROR("cellmap is lying");
1690 return NS_ERROR_FAILURE
;
1694 nsTableRowGroupFrame::FindLineContaining(nsIFrame
* aFrame
)
1696 NS_ENSURE_ARG_POINTER(aFrame
);
1698 NS_ASSERTION((aFrame
->GetType() == nsGkAtoms::tableRowFrame
),
1699 "RowGroup contains a frame that is not a row");
1701 nsTableRowFrame
* rowFrame
= (nsTableRowFrame
*)aFrame
;
1702 return rowFrame
->GetRowIndex() - GetStartRowIndex();
1706 nsTableRowGroupFrame::FindLineAt(nscoord aY
)
1708 NS_NOTREACHED("Not implemented");
1709 return NS_ERROR_NOT_IMPLEMENTED
;
1714 nsTableRowGroupFrame::CheckLineOrder(PRInt32 aLine
,
1715 PRBool
*aIsReordered
,
1716 nsIFrame
**aFirstVisual
,
1717 nsIFrame
**aLastVisual
)
1719 *aIsReordered
= PR_FALSE
;
1720 *aFirstVisual
= nsnull
;
1721 *aLastVisual
= nsnull
;
1727 nsTableRowGroupFrame::FindFrameAt(PRInt32 aLineNumber
,
1729 nsIFrame
** aFrameFound
,
1730 PRBool
* aXIsBeforeFirstFrame
,
1731 PRBool
* aXIsAfterLastFrame
)
1733 nsTableFrame
* table
= nsTableFrame::GetTableFrame(this);
1734 nsTableCellMap
* cellMap
= table
->GetCellMap();
1736 *aFrameFound
= nsnull
;
1737 *aXIsBeforeFirstFrame
= PR_TRUE
;
1738 *aXIsAfterLastFrame
= PR_FALSE
;
1740 aLineNumber
+= GetStartRowIndex();
1741 PRInt32 numCells
= cellMap
->GetNumCellsOriginatingInRow(aLineNumber
);
1742 if (numCells
== 0) {
1746 nsIFrame
* frame
= nsnull
;
1747 PRInt32 colCount
= table
->GetColCount();
1748 for (PRInt32 i
= 0; i
< colCount
; i
++) {
1749 CellData
* data
= cellMap
->GetDataAt(aLineNumber
, i
);
1750 if (data
&& data
->IsOrig()) {
1751 frame
= (nsIFrame
*)data
->GetCellFrame();
1755 NS_ASSERTION(frame
, "cellmap is lying");
1756 PRBool isRTL
= (NS_STYLE_DIRECTION_RTL
==
1757 table
->GetStyleVisibility()->mDirection
);
1759 nsIFrame
* closestFromLeft
= nsnull
;
1760 nsIFrame
* closestFromRight
= nsnull
;
1761 PRInt32 n
= numCells
;
1762 nsIFrame
* firstFrame
= frame
;
1764 nsRect rect
= frame
->GetRect();
1765 if (rect
.width
> 0) {
1766 // If aX is inside this frame - this is it
1767 if (rect
.x
<= aX
&& rect
.XMost() > aX
) {
1768 closestFromLeft
= closestFromRight
= frame
;
1772 if (!closestFromLeft
||
1773 rect
.XMost() > closestFromLeft
->GetRect().XMost())
1774 closestFromLeft
= frame
;
1777 if (!closestFromRight
||
1778 rect
.x
< closestFromRight
->GetRect().x
)
1779 closestFromRight
= frame
;
1782 frame
= frame
->GetNextSibling();
1784 if (!closestFromLeft
&& !closestFromRight
) {
1785 // All frames were zero-width. Just take the first one.
1786 closestFromLeft
= closestFromRight
= firstFrame
;
1788 *aXIsBeforeFirstFrame
= isRTL
? !closestFromRight
: !closestFromLeft
;
1789 *aXIsAfterLastFrame
= isRTL
? !closestFromLeft
: !closestFromRight
;
1790 if (closestFromLeft
== closestFromRight
) {
1791 *aFrameFound
= closestFromLeft
;
1793 else if (!closestFromLeft
) {
1794 *aFrameFound
= closestFromRight
;
1796 else if (!closestFromRight
) {
1797 *aFrameFound
= closestFromLeft
;
1799 else { // we're between two frames
1800 nscoord delta
= closestFromRight
->GetRect().x
-
1801 closestFromLeft
->GetRect().XMost();
1802 if (aX
< closestFromLeft
->GetRect().XMost() + delta
/2)
1803 *aFrameFound
= closestFromLeft
;
1805 *aFrameFound
= closestFromRight
;
1811 nsTableRowGroupFrame::GetNextSiblingOnLine(nsIFrame
*& aFrame
,
1812 PRInt32 aLineNumber
)
1814 NS_ENSURE_ARG_POINTER(aFrame
);
1815 aFrame
= aFrame
->GetNextSibling();
1819 //end nsLineIterator methods
1822 DestroyFrameCursorData(void* aObject
, nsIAtom
* aPropertyName
,
1823 void* aPropertyValue
, void* aData
)
1825 delete static_cast<nsTableRowGroupFrame::FrameCursorData
*>(aPropertyValue
);
1829 nsTableRowGroupFrame::ClearRowCursor()
1831 if (!(GetStateBits() & NS_ROWGROUP_HAS_ROW_CURSOR
))
1834 RemoveStateBits(NS_ROWGROUP_HAS_ROW_CURSOR
);
1835 DeleteProperty(nsGkAtoms::rowCursorProperty
);
1838 nsTableRowGroupFrame::FrameCursorData
*
1839 nsTableRowGroupFrame::SetupRowCursor()
1841 if (GetStateBits() & NS_ROWGROUP_HAS_ROW_CURSOR
) {
1842 // We already have a valid row cursor. Don't waste time rebuilding it.
1846 nsIFrame
* f
= mFrames
.FirstChild();
1848 for (count
= 0; f
&& count
< MIN_ROWS_NEEDING_CURSOR
; ++count
) {
1849 f
= f
->GetNextSibling();
1852 // Less than MIN_ROWS_NEEDING_CURSOR rows, so just don't bother
1856 FrameCursorData
* data
= new FrameCursorData();
1859 nsresult rv
= SetProperty(nsGkAtoms::rowCursorProperty
, data
,
1860 DestroyFrameCursorData
);
1861 if (NS_FAILED(rv
)) {
1865 AddStateBits(NS_ROWGROUP_HAS_ROW_CURSOR
);
1870 nsTableRowGroupFrame::GetFirstRowContaining(nscoord aY
, nscoord
* aOverflowAbove
)
1872 if (!(GetStateBits() & NS_ROWGROUP_HAS_ROW_CURSOR
))
1875 FrameCursorData
* property
= static_cast<FrameCursorData
*>
1876 (GetProperty(nsGkAtoms::rowCursorProperty
));
1877 PRUint32 cursorIndex
= property
->mCursorIndex
;
1878 PRUint32 frameCount
= property
->mFrames
.Length();
1879 if (cursorIndex
>= frameCount
)
1881 nsIFrame
* cursorFrame
= property
->mFrames
[cursorIndex
];
1883 // The cursor's frame list excludes frames with empty overflow-area, so
1884 // we don't need to check that here.
1886 // We use property->mOverflowBelow here instead of computing the frame's
1887 // true overflowArea.YMost(), because it is essential for the thresholds
1888 // to form a monotonically increasing sequence. Otherwise we would break
1889 // encountering a row whose overflowArea.YMost() is <= aY but which has
1890 // a row above it containing cell(s) that span to include aY.
1891 while (cursorIndex
> 0 &&
1892 cursorFrame
->GetRect().YMost() + property
->mOverflowBelow
> aY
) {
1894 cursorFrame
= property
->mFrames
[cursorIndex
];
1896 while (cursorIndex
+ 1 < frameCount
&&
1897 cursorFrame
->GetRect().YMost() + property
->mOverflowBelow
<= aY
) {
1899 cursorFrame
= property
->mFrames
[cursorIndex
];
1902 property
->mCursorIndex
= cursorIndex
;
1903 *aOverflowAbove
= property
->mOverflowAbove
;
1908 nsTableRowGroupFrame::FrameCursorData::AppendFrame(nsIFrame
* aFrame
)
1910 nsRect overflowRect
= aFrame
->GetOverflowRect();
1911 if (overflowRect
.IsEmpty())
1913 nscoord overflowAbove
= -overflowRect
.y
;
1914 nscoord overflowBelow
= overflowRect
.YMost() - aFrame
->GetSize().height
;
1915 mOverflowAbove
= PR_MAX(mOverflowAbove
, overflowAbove
);
1916 mOverflowBelow
= PR_MAX(mOverflowBelow
, overflowBelow
);
1917 return mFrames
.AppendElement(aFrame
) != nsnull
;