Back to index

lightning-sunbird  0.9+nobinonly
nsTableRowGroupFrame.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Mats Palmgren <mats.palmgren@bredband.net>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 #include "nsCOMPtr.h"
00039 #include "nsTableRowGroupFrame.h"
00040 #include "nsTableRowFrame.h"
00041 #include "nsTableFrame.h"
00042 #include "nsTableCellFrame.h"
00043 #include "nsIRenderingContext.h"
00044 #include "nsPresContext.h"
00045 #include "nsStyleContext.h"
00046 #include "nsStyleConsts.h"
00047 #include "nsIContent.h"
00048 #include "nsIView.h"
00049 #include "nsReflowPath.h"
00050 #include "nsIDeviceContext.h"
00051 #include "nsHTMLAtoms.h"
00052 #include "nsIPresShell.h"
00053 #include "nsLayoutAtoms.h"
00054 #include "nsCSSRendering.h"
00055 #include "nsHTMLParts.h"
00056 #include "nsCSSFrameConstructor.h"
00057 
00058 #include "nsCellMap.h"//table cell navigation
00059 
00060 nsTableRowGroupFrame::nsTableRowGroupFrame()
00061 {
00062   SetRepeatable(PR_FALSE);
00063 #ifdef DEBUG_TABLE_REFLOW_TIMING
00064   mTimer = new nsReflowTimer(this);
00065 #endif
00066 }
00067 
00068 nsTableRowGroupFrame::~nsTableRowGroupFrame()
00069 {
00070 #ifdef DEBUG_TABLE_REFLOW_TIMING
00071   nsTableFrame::DebugReflowDone(this);
00072 #endif
00073 }
00074 
00075 /* ----------- nsTableRowGroupFrame ---------- */
00076 nsrefcnt nsTableRowGroupFrame::AddRef(void)
00077 {
00078   return 1;//implementation of nsLineIterator
00079 }
00080 
00081 nsrefcnt nsTableRowGroupFrame::Release(void)
00082 {
00083   return 1;//implementation of nsLineIterator
00084 }
00085 
00086 
00087 nsresult
00088 nsTableRowGroupFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
00089 {
00090   if (NULL == aInstancePtr) {
00091     return NS_ERROR_NULL_POINTER;
00092   }
00093   static NS_DEFINE_IID(kITableRowGroupIID, NS_ITABLEROWGROUPFRAME_IID);
00094   if (aIID.Equals(kITableRowGroupIID)) {
00095     *aInstancePtr = (void*)this;
00096     return NS_OK;
00097   }
00098   else if (aIID.Equals(NS_GET_IID(nsILineIteratorNavigator)))
00099   { // note there is no addref here, frames are not addref'd
00100     *aInstancePtr = (void*)(nsILineIteratorNavigator*)this;
00101     return NS_OK;
00102   }
00103   else {
00104     return nsHTMLContainerFrame::QueryInterface(aIID, aInstancePtr);
00105   }
00106 }
00107 
00108 /* virtual */ PRBool
00109 nsTableRowGroupFrame::IsContainingBlock() const
00110 {
00111   return PR_TRUE;
00112 }
00113 
00114 PRInt32
00115 nsTableRowGroupFrame::GetRowCount()
00116 {  
00117   PRInt32 count = 0; // init return
00118 
00119   // loop through children, adding one to aCount for every legit row
00120   nsIFrame* childFrame = GetFirstFrame();
00121   while (PR_TRUE) {
00122     if (!childFrame)
00123       break;
00124     if (NS_STYLE_DISPLAY_TABLE_ROW == childFrame->GetStyleDisplay()->mDisplay)
00125       count++;
00126     GetNextFrame(childFrame, &childFrame);
00127   }
00128   return count;
00129 }
00130 
00131 PRInt32 nsTableRowGroupFrame::GetStartRowIndex()
00132 {
00133   PRInt32 result = -1;
00134   nsIFrame* childFrame = GetFirstFrame();
00135   while (PR_TRUE) {
00136     if (!childFrame)
00137       break;
00138     if (NS_STYLE_DISPLAY_TABLE_ROW == childFrame->GetStyleDisplay()->mDisplay) {
00139       result = ((nsTableRowFrame *)childFrame)->GetRowIndex();
00140       break;
00141     }
00142     GetNextFrame(childFrame, &childFrame);
00143   }
00144   // if the row group doesn't have any children, get it the hard way
00145   if (-1 == result) {
00146     nsTableFrame* tableFrame;
00147     nsTableFrame::GetTableFrame(this, tableFrame);
00148     if (tableFrame) {
00149       return tableFrame->GetStartRowIndex(*this);
00150     }
00151   }
00152       
00153   return result;
00154 }
00155 
00156 void  nsTableRowGroupFrame::AdjustRowIndices(PRInt32 aRowIndex,
00157                                              PRInt32 anAdjustment)
00158 {
00159   nsIFrame* rowFrame = GetFirstChild(nsnull);
00160   for ( ; rowFrame; rowFrame = rowFrame->GetNextSibling()) {
00161     if (NS_STYLE_DISPLAY_TABLE_ROW==rowFrame->GetStyleDisplay()->mDisplay) {
00162       PRInt32 index = ((nsTableRowFrame*)rowFrame)->GetRowIndex();
00163       if (index >= aRowIndex)
00164         ((nsTableRowFrame *)rowFrame)->SetRowIndex(index+anAdjustment);
00165     }
00166   }
00167 }
00168 nsresult
00169 nsTableRowGroupFrame::InitRepeatedFrame(nsPresContext*       aPresContext,
00170                                         nsTableRowGroupFrame* aHeaderFooterFrame)
00171 {
00172   nsTableRowFrame* copyRowFrame = GetFirstRow();
00173   nsTableRowFrame* originalRowFrame = aHeaderFooterFrame->GetFirstRow();
00174   AddStateBits(NS_REPEATED_ROW_OR_ROWGROUP);
00175   while (copyRowFrame && originalRowFrame) {
00176     copyRowFrame->AddStateBits(NS_REPEATED_ROW_OR_ROWGROUP);
00177     int rowIndex = originalRowFrame->GetRowIndex();
00178     copyRowFrame->SetRowIndex(rowIndex);
00179 
00180     // For each table cell frame set its column index
00181     nsTableCellFrame* originalCellFrame = originalRowFrame->GetFirstCell();
00182     nsTableCellFrame* copyCellFrame     = copyRowFrame->GetFirstCell();
00183     while (copyCellFrame && originalCellFrame) {
00184       NS_ASSERTION(originalCellFrame->GetContent() == copyCellFrame->GetContent(),
00185                    "cell frames have different content");
00186       PRInt32 colIndex;
00187       originalCellFrame->GetColIndex(colIndex);
00188       copyCellFrame->SetColIndex(colIndex);
00189         
00190       // Move to the next cell frame
00191       copyCellFrame     = copyCellFrame->GetNextCell();
00192       originalCellFrame = originalCellFrame->GetNextCell();
00193     }
00194     
00195     // Move to the next row frame
00196     originalRowFrame = originalRowFrame->GetNextRow();
00197     copyRowFrame = copyRowFrame->GetNextRow();
00198   }
00199 
00200   return NS_OK;
00201 }
00202 
00203 NS_METHOD nsTableRowGroupFrame::Paint(nsPresContext*      aPresContext,
00204                                       nsIRenderingContext& aRenderingContext,
00205                                       const nsRect&        aDirtyRect,
00206                                       nsFramePaintLayer    aWhichLayer,
00207                                       PRUint32             aFlags)
00208 {
00209   PRBool isVisible;
00210   if (NS_SUCCEEDED(IsVisibleForPainting(aPresContext, aRenderingContext, PR_FALSE, &isVisible)) && !isVisible) {
00211     return NS_OK;
00212   }
00213 
00214 #ifdef DEBUG
00215   // for debug...
00216   if ((NS_FRAME_PAINT_LAYER_DEBUG == aWhichLayer) && GetShowFrameBorders()) {
00217     aRenderingContext.SetColor(NS_RGB(0,255,0));
00218     aRenderingContext.DrawRect(0, 0, mRect.width, mRect.height);
00219   }
00220 #endif
00221 
00222   if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer &&
00223       //direct (not table-called) background paint
00224       !(aFlags & (NS_PAINT_FLAG_TABLE_BG_PAINT | NS_PAINT_FLAG_TABLE_CELL_BG_PASS))) {
00225     nsTableFrame* tableFrame;
00226     nsTableFrame::GetTableFrame(this, tableFrame);
00227     NS_ASSERTION(tableFrame, "null table frame");
00228 
00229     TableBackgroundPainter painter(tableFrame,
00230                                    TableBackgroundPainter::eOrigin_TableRowGroup,
00231                                    aPresContext, aRenderingContext,
00232                                    aDirtyRect);
00233     nsresult rv = painter.PaintRowGroup(this);
00234     if (NS_FAILED(rv)) return rv;
00235     aFlags |= NS_PAINT_FLAG_TABLE_BG_PAINT;
00236   }
00237 
00238   PaintChildren(aPresContext, aRenderingContext, aDirtyRect,
00239                 aWhichLayer, aFlags);
00240 
00241   // Paint outline
00242   nsRect rect(0, 0, mRect.width, mRect.height);
00243   const nsStyleOutline* outlineStyle = GetStyleOutline();
00244   const nsStyleBorder* borderStyle  = GetStyleBorder();
00245   nsCSSRendering::PaintOutline(aPresContext, aRenderingContext, this,
00246                                aDirtyRect, rect, *borderStyle, *outlineStyle,
00247                                mStyleContext, 0);
00248   return NS_OK;
00249 }
00250 
00251 PRIntn
00252 nsTableRowGroupFrame::GetSkipSides() const
00253 {
00254   PRIntn skip = 0;
00255   if (nsnull != mPrevInFlow) {
00256     skip |= 1 << NS_SIDE_TOP;
00257   }
00258   if (nsnull != mNextInFlow) {
00259     skip |= 1 << NS_SIDE_BOTTOM;
00260   }
00261   return skip;
00262 }
00263 
00264 
00265 NS_IMETHODIMP
00266 nsTableRowGroupFrame::GetFrameForPoint(const nsPoint& aPoint, 
00267                                    nsFramePaintLayer aWhichLayer,
00268                                    nsIFrame**     aFrame)
00269 {
00270   // this should act like a block, so we need to override
00271   return GetFrameForPointUsing(aPoint, nsnull, aWhichLayer, PR_FALSE, aFrame);
00272 }
00273 
00274 // Position and size aKidFrame and update our reflow state. The origin of
00275 // aKidRect is relative to the upper-left origin of our frame
00276 void 
00277 nsTableRowGroupFrame::PlaceChild(nsPresContext*        aPresContext,
00278                                  nsRowGroupReflowState& aReflowState,
00279                                  nsIFrame*              aKidFrame,
00280                                  nsHTMLReflowMetrics&   aDesiredSize)
00281 {
00282   // Place and size the child
00283   FinishReflowChild(aKidFrame, aPresContext, nsnull, aDesiredSize, 0, aReflowState.y, 0);
00284 
00285   // Adjust the running y-offset
00286   aReflowState.y += aDesiredSize.height;
00287 
00288   // If our height is constrained then update the available height
00289   if (NS_UNCONSTRAINEDSIZE != aReflowState.availSize.height) {
00290     aReflowState.availSize.height -= aDesiredSize.height;
00291   }
00292 }
00293 
00294 void
00295 nsTableRowGroupFrame::InitChildReflowState(nsPresContext&    aPresContext, 
00296                                            PRBool             aBorderCollapse,
00297                                            float              aPixelsToTwips,
00298                                            nsHTMLReflowState& aReflowState)                                    
00299 {
00300   nsMargin collapseBorder;
00301   nsMargin padding(0,0,0,0);
00302   nsMargin* pCollapseBorder = nsnull;
00303   if (aBorderCollapse) {
00304     if (aReflowState.frame) {
00305       if (nsLayoutAtoms::tableRowFrame == aReflowState.frame->GetType()) {
00306         nsTableRowFrame* rowFrame = (nsTableRowFrame*)aReflowState.frame;
00307         pCollapseBorder = rowFrame->GetBCBorderWidth(aPixelsToTwips, collapseBorder);
00308       }
00309     }
00310   }
00311   aReflowState.Init(&aPresContext, -1, -1, pCollapseBorder, &padding);
00312 }
00313 
00314 // Reflow the frames we've already created. If aDirtyOnly is set then only
00315 // reflow dirty frames. This assumes that all of the dirty frames are contiguous.
00316 NS_METHOD 
00317 nsTableRowGroupFrame::ReflowChildren(nsPresContext*        aPresContext,
00318                                      nsHTMLReflowMetrics&   aDesiredSize,
00319                                      nsRowGroupReflowState& aReflowState,
00320                                      nsReflowStatus&        aStatus,
00321                                      nsTableRowFrame*       aStartFrame,
00322                                      PRBool                 aDirtyOnly,
00323                                      nsTableRowFrame**      aFirstRowReflowed,
00324                                      PRBool*                aPageBreakBeforeEnd)
00325 {
00326   if (aPageBreakBeforeEnd) 
00327     *aPageBreakBeforeEnd = PR_FALSE;
00328 
00329   nsTableFrame* tableFrame = nsnull;
00330   nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame); if (!tableFrame) ABORT1(rv);
00331 
00332   PRBool borderCollapse = tableFrame->IsBorderCollapse();
00333   GET_PIXELS_TO_TWIPS(aPresContext, p2t);
00334 
00335   nscoord cellSpacingY = tableFrame->GetCellSpacingY();
00336 
00337   PRBool isPaginated = aPresContext->IsPaginated();
00338 
00339   if (aFirstRowReflowed) {
00340     *aFirstRowReflowed = nsnull;
00341   }
00342   nsIFrame* lastReflowedRow = nsnull;
00343   PRBool    adjustSiblings  = PR_TRUE;
00344   nsIFrame* kidFrame = (aStartFrame) ? aStartFrame : mFrames.FirstChild();
00345 
00346   for ( ; kidFrame; kidFrame = kidFrame->GetNextSibling()) {
00347     // See if we should only reflow the dirty child frames
00348     PRBool doReflowChild = PR_TRUE;
00349     if (aDirtyOnly && ((kidFrame->GetStateBits() & NS_FRAME_IS_DIRTY) == 0)) {
00350       doReflowChild = PR_FALSE;
00351     }
00352     nsIAtom* kidType = kidFrame->GetType();
00353     if (aReflowState.reflowState.mFlags.mSpecialHeightReflow) {
00354       if (!isPaginated && (nsLayoutAtoms::tableRowFrame == kidType &&
00355                            !((nsTableRowFrame*)kidFrame)->NeedSpecialReflow())) {
00356         doReflowChild = PR_FALSE;
00357       }
00358     }
00359 
00360     // Reflow the row frame
00361     if (doReflowChild) {
00362       nsSize kidAvailSize(aReflowState.availSize);
00363       if (0 >= kidAvailSize.height)
00364         kidAvailSize.height = 1;      // XXX: HaCk - we don't handle negative heights yet
00365       nsHTMLReflowMetrics desiredSize(aDesiredSize.mComputeMEW);
00366       desiredSize.width = desiredSize.height = desiredSize.ascent = desiredSize.descent = 0;
00367   
00368       // Reflow the child into the available space, giving it as much height as
00369       // it wants. We'll deal with splitting later after we've computed the row
00370       // heights, taking into account cells with row spans...
00371       kidAvailSize.height = NS_UNCONSTRAINEDSIZE;
00372       // If the incremental reflow command is a StyleChanged reflow and
00373       // it's target is the current frame, then make sure we send
00374       // StyleChange reflow reasons down to the children so that they
00375       // don't over-optimize their reflow.
00376       nsReflowReason reason = aReflowState.reason;
00377       if (eReflowReason_Incremental == aReflowState.reason) {
00378         nsHTMLReflowCommand* command = aReflowState.reflowState.path->mReflowCommand;
00379         if (command) {
00380           nsReflowType type;
00381           command->GetType(type);
00382           if (eReflowType_StyleChanged == type) {
00383             reason = eReflowReason_StyleChange;
00384           }
00385         }
00386       }
00387       if (kidFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) {
00388         reason = eReflowReason_Initial;
00389       }
00390       nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState, kidFrame,
00391                                        kidAvailSize, reason);
00392       InitChildReflowState(*aPresContext, borderCollapse, p2t, kidReflowState);
00393      
00394       // If this isn't the first row, then we can't be at the top of the page
00395       if (kidFrame != GetFirstFrame()) {
00396         kidReflowState.mFlags.mIsTopOfPage = PR_FALSE;
00397       }
00398 
00399       rv = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState,
00400                        0, aReflowState.y, 0, aStatus);
00401 
00402       // Place the child
00403       PlaceChild(aPresContext, aReflowState, kidFrame, desiredSize);
00404       aReflowState.y += cellSpacingY;
00405       lastReflowedRow = kidFrame;
00406 
00407       if (aFirstRowReflowed && !*aFirstRowReflowed) { 
00408         if (nsLayoutAtoms::tableRowFrame == kidType) {
00409           *aFirstRowReflowed = (nsTableRowFrame*)kidFrame;
00410         }
00411       }
00412       if (isPaginated && aPageBreakBeforeEnd && !*aPageBreakBeforeEnd && 
00413           (nsLayoutAtoms::tableRowFrame == kidType)) {
00414         nsTableRowFrame* nextRow = ((nsTableRowFrame*)kidFrame)->GetNextRow();
00415         if (nextRow) {
00416           *aPageBreakBeforeEnd = nsTableFrame::PageBreakAfter(*kidFrame, nextRow);
00417         }
00418       }
00419     } else {
00420       // were done reflowing, so see if we need to reposition the rows that follow
00421       if (lastReflowedRow) { 
00422         if (tableFrame->NeedsReflow(aReflowState.reflowState)) {
00423           adjustSiblings = PR_FALSE;
00424           break; // don't bother if the table will reflow everything.
00425         }
00426       }
00427       // Adjust the running y-offset so we know where the next row should be placed
00428       aReflowState.y += kidFrame->GetSize().height + cellSpacingY;
00429     }
00430     ConsiderChildOverflow(aDesiredSize.mOverflowArea, kidFrame);
00431   }
00432 
00433   // adjust the rows after the ones that were reflowed
00434   if (lastReflowedRow && adjustSiblings) {
00435     nsIFrame* nextRow = lastReflowedRow->GetNextSibling();
00436     if (nextRow) {
00437       nscoord deltaY = cellSpacingY + lastReflowedRow->GetRect().YMost()
00438         - nextRow->GetPosition().y;
00439       if (deltaY != 0) {
00440         AdjustSiblingsAfterReflow(aReflowState, lastReflowedRow, deltaY);
00441       }
00442     }
00443   }
00444 
00445   if (aReflowState.reflowState.mFlags.mSpecialHeightReflow) {
00446     aDesiredSize.height = mRect.height;
00447   }
00448   return rv;
00449 }
00450 
00451 nsTableRowFrame*  
00452 nsTableRowGroupFrame::GetFirstRow() 
00453 {
00454   for (nsIFrame* childFrame = GetFirstFrame(); childFrame;
00455        childFrame = childFrame->GetNextSibling()) {
00456     if (nsLayoutAtoms::tableRowFrame == childFrame->GetType()) {
00457       return (nsTableRowFrame*)childFrame;
00458     }
00459   }
00460   return nsnull;
00461 }
00462 
00463 
00464 struct RowInfo {
00465   RowInfo() { height = pctHeight = hasStyleHeight = hasPctHeight = isSpecial = 0; }
00466   unsigned height;       // content height or fixed height, excluding pct height
00467   unsigned pctHeight:29; // pct height
00468   unsigned hasStyleHeight:1; 
00469   unsigned hasPctHeight:1; 
00470   unsigned isSpecial:1; // there is no cell originating in the row with rowspan=1 and there are at
00471                         // least 2 cells spanning the row and there is no style height on the row
00472 };
00473 
00474 static void
00475 UpdateHeights(RowInfo& aRowInfo,
00476               nscoord  aAdditionalHeight,
00477               nscoord& aTotal,
00478               nscoord& aUnconstrainedTotal)
00479 {
00480   aRowInfo.height += aAdditionalHeight;
00481   aTotal          += aAdditionalHeight;
00482   if (!aRowInfo.hasStyleHeight) {
00483     aUnconstrainedTotal += aAdditionalHeight;
00484   }
00485 }
00486 
00487 void 
00488 nsTableRowGroupFrame::DidResizeRows(nsPresContext&          aPresContext,
00489                                     const nsHTMLReflowState& aReflowState,
00490                                     nsHTMLReflowMetrics&     aDesiredSize,
00491                                     nsTableRowFrame*         aStartRowFrameIn)
00492 {
00493   // update the cells spanning rows with their new heights
00494   // this is the place where all of the cells in the row get set to the height of the row
00495   PRInt32 rowIndex;
00496   nsTableRowFrame* rowFrame;
00497   nsTableRowFrame* startRowFrame = (aStartRowFrameIn) ? aStartRowFrameIn: GetFirstRow();
00498   if (!aStartRowFrameIn || startRowFrame == GetFirstRow()) {
00499     // Reset the overflow area
00500     aDesiredSize.mOverflowArea = nsRect(0, 0, 0, 0);
00501   }
00502   for (rowFrame = startRowFrame, rowIndex = 0; rowFrame; rowFrame = rowFrame->GetNextRow(), rowIndex++) {
00503     rowFrame->DidResize(&aPresContext, aReflowState);
00504     ConsiderChildOverflow(aDesiredSize.mOverflowArea, rowFrame);
00505   }
00506 }
00507 
00508 static void
00509 CacheRowHeightsForPrinting(nsPresContext*  aPresContext,
00510                            nsTableRowFrame* aFirstRow)
00511 {
00512   for (nsTableRowFrame* row = aFirstRow; row; row = row->GetNextRow()) {
00513     if (!row->GetPrevInFlow()) {
00514       row->SetHasUnpaginatedHeight(PR_TRUE);
00515       row->SetUnpaginatedHeight(aPresContext, row->GetSize().height);
00516     }
00517   }
00518 }
00519 
00520 // This calculates the height of rows starting at aStartRowFrameIn and takes into account 
00521 // style height on the row group, style heights on rows and cells, style heights on rowspans. 
00522 // Actual row heights will be adjusted later if the table has a style height.
00523 // Even if rows don't change height, this method must be called to set the heights of each
00524 // cell in the row to the height of its row.
00525 void 
00526 nsTableRowGroupFrame::CalculateRowHeights(nsPresContext*          aPresContext, 
00527                                           nsHTMLReflowMetrics&     aDesiredSize,
00528                                           const nsHTMLReflowState& aReflowState,
00529                                           nsTableRowFrame*         aStartRowFrameIn)
00530 {
00531   nsTableFrame* tableFrame = nsnull;
00532   nsTableFrame::GetTableFrame(this, tableFrame);
00533   if (!tableFrame) return;
00534 
00535   PRBool isPaginated = aPresContext->IsPaginated();
00536 
00537   // all table cells have the same top and bottom margins, namely cellSpacingY
00538   nscoord cellSpacingY = tableFrame->GetCellSpacingY();
00539   float p2t;
00540   p2t = aPresContext->PixelsToTwips();
00541 
00542   // find the nearest row index at or before aStartRowFrameIn that isn't spanned into. 
00543   // If we have a computed height, then we can't compute the heights
00544   // incrementally from aStartRowFrameIn, and we must start at the first row.
00545   PRInt32 rgStart = GetStartRowIndex();
00546   PRInt32 startRowIndex = (aStartRowFrameIn) ? aStartRowFrameIn->GetRowIndex() : rgStart;
00547   PRInt32 startRowIndexSave = startRowIndex;
00548   if ((NS_UNCONSTRAINEDSIZE != aReflowState.mComputedHeight) && (aReflowState.mComputedHeight > 0)) {
00549     startRowIndex = rgStart;
00550   }
00551   else {
00552     while (startRowIndex > rgStart) {
00553       if (!tableFrame->RowIsSpannedInto(startRowIndex)) 
00554         break;
00555       startRowIndex--;
00556     }
00557   }
00558   // find the row corresponding to the row index we just found
00559   nsTableRowFrame* startRowFrame = aStartRowFrameIn;
00560   if (!startRowFrame || (startRowIndex != startRowIndexSave)) {
00561     PRInt32 rowX = rgStart;
00562     for (startRowFrame = GetFirstRow(); startRowFrame; startRowFrame = startRowFrame->GetNextRow()) {
00563       if (rowX >= startRowIndex)
00564         break;
00565       rowX++;
00566     }
00567   }
00568       
00569   if (!startRowFrame) return;
00570 
00571   // the current row group height is the y origin of the 1st row we are about to calculated a height for
00572   nscoord startRowGroupHeight = startRowFrame->GetPosition().y;
00573 
00574   PRInt32 numRows = GetRowCount() - (startRowFrame->GetRowIndex() - GetStartRowIndex());
00575   // collect the current height of each row.  nscoord* rowHeights = nsnull;
00576   RowInfo* rowInfo;
00577   if (numRows > 0) {
00578     rowInfo = new RowInfo[numRows];
00579     if (!rowInfo) return;
00580     memset (rowInfo, 0, numRows*sizeof(RowInfo));
00581   } 
00582   else return;
00583 
00584   PRBool  hasRowSpanningCell = PR_FALSE;
00585   nscoord heightOfRows = 0;
00586   nscoord heightOfUnStyledRows = 0;
00587   // Get the height of each row without considering rowspans. This will be the max of 
00588   // the largest desired height of each cell, the largest style height of each cell, 
00589   // the style height of the row.
00590   nscoord pctHeightBasis = GetHeightBasis(aReflowState);
00591   PRInt32 rowIndex; // the index in rowInfo, not among the rows in the row group
00592   nsTableRowFrame* rowFrame;
00593   for (rowFrame = startRowFrame, rowIndex = 0; rowFrame; rowFrame = rowFrame->GetNextRow(), rowIndex++) {
00594     nscoord nonPctHeight = rowFrame->GetContentHeight();
00595     if (isPaginated) {
00596       nonPctHeight = PR_MAX(nonPctHeight, rowFrame->GetSize().height);
00597     }
00598     if (!rowFrame->GetPrevInFlow()) {
00599       if (rowFrame->HasPctHeight()) {
00600         rowInfo[rowIndex].hasPctHeight = PR_TRUE;
00601         rowInfo[rowIndex].pctHeight = nsTableFrame::RoundToPixel(rowFrame->GetHeight(pctHeightBasis), p2t);
00602       }
00603       rowInfo[rowIndex].hasStyleHeight = rowFrame->HasStyleHeight();
00604       nonPctHeight = nsTableFrame::RoundToPixel(PR_MAX(nonPctHeight, rowFrame->GetFixedHeight()), p2t);
00605     }
00606     UpdateHeights(rowInfo[rowIndex], nonPctHeight, heightOfRows, heightOfUnStyledRows);
00607 
00608     if (!rowInfo[rowIndex].hasStyleHeight) {
00609       if (isPaginated || tableFrame->HasMoreThanOneCell(rowIndex + startRowIndex)) {
00610         rowInfo[rowIndex].isSpecial = PR_TRUE;
00611         // iteratate the row's cell frames to see if any do not have rowspan > 1
00612         nsTableCellFrame* cellFrame = rowFrame->GetFirstCell();
00613         while (cellFrame) {
00614           PRInt32 rowSpan = tableFrame->GetEffectiveRowSpan(rowIndex + startRowIndex, *cellFrame);
00615           if (1 == rowSpan) { 
00616             rowInfo[rowIndex].isSpecial = PR_FALSE;
00617             break;
00618           }
00619           cellFrame = cellFrame->GetNextCell(); 
00620         }
00621       }
00622     }
00623     // See if a cell spans into the row. If so we'll have to do the next step
00624     if (!hasRowSpanningCell) {
00625       if (tableFrame->RowIsSpannedInto(rowIndex + startRowIndex)) {
00626         hasRowSpanningCell = PR_TRUE;
00627       }
00628     }
00629   }
00630 
00631   if (hasRowSpanningCell) {
00632     // Get the height of cells with rowspans and allocate any extra space to the rows they span 
00633     // iteratate the child frames and process the row frames among them
00634     for (rowFrame = startRowFrame, rowIndex = 0; rowFrame; rowFrame = rowFrame->GetNextRow(), rowIndex++) {
00635       // See if the row has an originating cell with rowspan > 1. We cannot determine this for a row in a 
00636       // continued row group by calling RowHasSpanningCells, because the row's fif may not have any originating
00637       // cells yet the row may have a continued cell which originates in it.
00638       if (mPrevInFlow || tableFrame->RowHasSpanningCells(startRowIndex + rowIndex)) {
00639         nsTableCellFrame* cellFrame = rowFrame->GetFirstCell();
00640         // iteratate the row's cell frames 
00641         while (cellFrame) {
00642           PRInt32 rowSpan = tableFrame->GetEffectiveRowSpan(rowIndex + startRowIndex, *cellFrame);
00643           if ((rowIndex + rowSpan) > numRows) {
00644             // there might be rows pushed already to the nextInFlow
00645             rowSpan = numRows - rowIndex;
00646           }
00647           if (rowSpan > 1) { // a cell with rowspan > 1, determine the height of the rows it spans
00648             nscoord heightOfRowsSpanned = 0;
00649             nscoord heightOfUnStyledRowsSpanned = 0;
00650             nscoord numSpecialRowsSpanned = 0; 
00651             nscoord cellSpacingTotal = 0;
00652             PRInt32 spanX;
00653             for (spanX = 0; spanX < rowSpan; spanX++) {
00654               heightOfRowsSpanned += rowInfo[rowIndex + spanX].height;
00655               if (!rowInfo[rowIndex + spanX].hasStyleHeight) {
00656                 heightOfUnStyledRowsSpanned += rowInfo[rowIndex + spanX].height;
00657               }
00658               if (0 != spanX) {
00659                 cellSpacingTotal += cellSpacingY;
00660               }
00661               if (rowInfo[rowIndex + spanX].isSpecial) {
00662                 numSpecialRowsSpanned++;
00663               }
00664             } 
00665             nscoord heightOfAreaSpanned = heightOfRowsSpanned + cellSpacingTotal;
00666             // get the height of the cell 
00667             nsSize cellFrameSize = cellFrame->GetSize();
00668             nsSize cellDesSize = cellFrame->GetDesiredSize();
00669             rowFrame->CalculateCellActualSize(cellFrame, cellDesSize.width, 
00670                                               cellDesSize.height, cellDesSize.width);
00671             cellFrameSize.height = cellDesSize.height;
00672             if (cellFrame->HasVerticalAlignBaseline()) {
00673               // to ensure that a spanning cell with a long descender doesn't
00674               // collide with the next row, we need to take into account the shift
00675               // that will be done to align the cell on the baseline of the row.
00676               cellFrameSize.height += rowFrame->GetMaxCellAscent() - cellFrame->GetDesiredAscent();
00677             }
00678   
00679             if (heightOfAreaSpanned < cellFrameSize.height) {
00680               // the cell's height is larger than the available space of the rows it
00681               // spans so distribute the excess height to the rows affected
00682               nscoord extra     = cellFrameSize.height - heightOfAreaSpanned;
00683               nscoord extraUsed = 0;
00684               if (0 == numSpecialRowsSpanned) {
00685                 //NS_ASSERTION(heightOfRowsSpanned > 0, "invalid row span situation");
00686                 PRBool haveUnStyledRowsSpanned = (heightOfUnStyledRowsSpanned > 0);
00687                 nscoord divisor = (haveUnStyledRowsSpanned) 
00688                                   ? heightOfUnStyledRowsSpanned : heightOfRowsSpanned;
00689                 if (divisor > 0) {
00690                   for (spanX = rowSpan - 1; spanX >= 0; spanX--) {
00691                     if (!haveUnStyledRowsSpanned || !rowInfo[rowIndex + spanX].hasStyleHeight) {
00692                       // The amount of additional space each row gets is proportional to its height
00693                       float percent = ((float)rowInfo[rowIndex + spanX].height) / ((float)divisor);
00694                     
00695                       // give rows their percentage, except for the first row which gets the remainder
00696                       nscoord extraForRow = (0 == spanX) ? extra - extraUsed  
00697                                                          : NSToCoordRound(((float)(extra)) * percent);
00698                       extraForRow = PR_MIN(nsTableFrame::RoundToPixel(extraForRow, p2t), extra - extraUsed);
00699                       // update the row height
00700                       UpdateHeights(rowInfo[rowIndex + spanX], extraForRow, heightOfRows, heightOfUnStyledRows);
00701                       extraUsed += extraForRow;
00702                       if (extraUsed >= extra) {
00703                         NS_ASSERTION((extraUsed == extra), "invalid row height calculation");
00704                         break;
00705                       }
00706                     }
00707                   }
00708                 }
00709                 else {
00710                   // put everything in the last row
00711                   UpdateHeights(rowInfo[rowIndex + rowSpan - 1], extra, heightOfRows, heightOfUnStyledRows);
00712                 }
00713               }
00714               else {
00715                 // give the extra to the special rows
00716                 nscoord numSpecialRowsAllocated = 0;
00717                 for (spanX = rowSpan - 1; spanX >= 0; spanX--) {
00718                   if (rowInfo[rowIndex + spanX].isSpecial) {
00719                     // The amount of additional space each degenerate row gets is proportional to the number of them
00720                     float percent = 1.0f / ((float)numSpecialRowsSpanned);
00721                     
00722                     // give rows their percentage, except for the first row which gets the remainder
00723                     nscoord extraForRow = (numSpecialRowsSpanned - 1 == numSpecialRowsAllocated) 
00724                                           ? extra - extraUsed  
00725                                           : NSToCoordRound(((float)(extra)) * percent);
00726                     extraForRow = PR_MIN(nsTableFrame::RoundToPixel(extraForRow, p2t), extra - extraUsed);
00727                     // update the row height
00728                     UpdateHeights(rowInfo[rowIndex + spanX], extraForRow, heightOfRows, heightOfUnStyledRows);
00729                     extraUsed += extraForRow;
00730                     if (extraUsed >= extra) {
00731                       NS_ASSERTION((extraUsed == extra), "invalid row height calculation");
00732                       break;
00733                     }
00734                   }
00735                 }
00736               }
00737             } 
00738           } // if (rowSpan > 1)
00739           cellFrame = cellFrame->GetNextCell(); 
00740         } // while (cellFrame)
00741       } // if (tableFrame->RowHasSpanningCells(startRowIndex + rowIndex) {
00742     } // while (rowFrame)
00743   }
00744 
00745   // pct height rows have already got their content heights. Give them their pct heights up to pctHeightBasis
00746   nscoord extra = pctHeightBasis - heightOfRows;
00747   for (rowFrame = startRowFrame, rowIndex = 0; rowFrame && (extra > 0); rowFrame = rowFrame->GetNextRow(), rowIndex++) {
00748     RowInfo& rInfo = rowInfo[rowIndex];
00749     if (rInfo.hasPctHeight) {
00750       nscoord rowExtra = (rInfo.pctHeight > rInfo.height)  
00751                          ? rInfo.pctHeight - rInfo.height: 0;
00752       rowExtra = PR_MIN(rowExtra, extra);
00753       UpdateHeights(rInfo, rowExtra, heightOfRows, heightOfUnStyledRows);
00754       extra -= rowExtra;
00755     }
00756   }
00757 
00758   PRBool styleHeightAllocation = PR_FALSE;
00759   nscoord rowGroupHeight = startRowGroupHeight + heightOfRows + ((numRows - 1) * cellSpacingY);
00760   // if we have a style height, allocate the extra height to unconstrained rows
00761   if ((aReflowState.mComputedHeight > rowGroupHeight) && 
00762       (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedHeight)) {
00763     nscoord extraComputedHeight = aReflowState.mComputedHeight - rowGroupHeight;
00764     nscoord extraUsed = 0;
00765     PRBool haveUnStyledRows = (heightOfUnStyledRows > 0);
00766     nscoord divisor = (haveUnStyledRows) 
00767                       ? heightOfUnStyledRows : heightOfRows;
00768     if (divisor > 0) {
00769       styleHeightAllocation = PR_TRUE;
00770       for (rowIndex = 0; rowIndex < numRows; rowIndex++) {
00771         if (!haveUnStyledRows || !rowInfo[rowIndex].hasStyleHeight) {
00772           // The amount of additional space each row gets is based on the
00773           // percentage of space it occupies
00774           float percent = ((float)rowInfo[rowIndex].height) / ((float)divisor);
00775           // give rows their percentage, except for the last row which gets the remainder
00776           nscoord extraForRow = (numRows - 1 == rowIndex) 
00777                                 ? extraComputedHeight - extraUsed  
00778                                 : NSToCoordRound(((float)extraComputedHeight) * percent);
00779           extraForRow = PR_MIN(nsTableFrame::RoundToPixel(extraForRow, p2t), extraComputedHeight - extraUsed);
00780           // update the row height
00781           UpdateHeights(rowInfo[rowIndex], extraForRow, heightOfRows, heightOfUnStyledRows);
00782           extraUsed += extraForRow;
00783           if (extraUsed >= extraComputedHeight) {
00784             NS_ASSERTION((extraUsed == extraComputedHeight), "invalid row height calculation");
00785             break;
00786           }
00787         }
00788       }
00789     }
00790     rowGroupHeight = aReflowState.mComputedHeight;
00791   }
00792 
00793   nscoord yOrigin = startRowGroupHeight;
00794   // update the rows with their (potentially) new heights
00795   for (rowFrame = startRowFrame, rowIndex = 0; rowFrame; rowFrame = rowFrame->GetNextRow(), rowIndex++) {
00796     nsRect rowBounds = rowFrame->GetRect(); 
00797 
00798     PRBool movedFrame = (rowBounds.y != yOrigin);  
00799     nscoord rowHeight = (rowInfo[rowIndex].height > 0) ? rowInfo[rowIndex].height : 0;
00800     
00801     if (movedFrame || (rowHeight != rowBounds.height)) {
00802       // Resize the row to its final size and position
00803       rowBounds.y = yOrigin;
00804       rowBounds.height = rowHeight;
00805       rowFrame->SetRect(rowBounds);
00806     }
00807     if (movedFrame) {
00808       nsTableFrame::RePositionViews(rowFrame);
00809     }
00810     yOrigin += rowHeight + cellSpacingY;
00811   }
00812 
00813   if (isPaginated && styleHeightAllocation) {
00814     // since the row group has a style height, cache the row heights, so next in flows can honor them 
00815     CacheRowHeightsForPrinting(aPresContext, GetFirstRow());
00816   }
00817 
00818   DidResizeRows(*aPresContext, aReflowState, aDesiredSize, startRowFrame);
00819 
00820   aDesiredSize.height = rowGroupHeight; // Adjust our desired size
00821   delete [] rowInfo; // cleanup
00822 }
00823 
00824 
00825 // Called by IR_TargetIsChild() to adjust the sibling frames that follow
00826 // after an incremental reflow of aKidFrame.
00827 // This function is not used for paginated mode so we don't need to deal
00828 // with continuing frames, and it's only called if aKidFrame has no
00829 // cells that span into it and no cells that span across it. That way
00830 // we don't have to deal with rowspans
00831 nsresult
00832 nsTableRowGroupFrame::AdjustSiblingsAfterReflow(nsRowGroupReflowState& aReflowState,
00833                                                 nsIFrame*              aKidFrame,
00834                                                 nscoord                aDeltaY)
00835 {
00836   NS_PRECONDITION(NS_UNCONSTRAINEDSIZE == aReflowState.reflowState.availableHeight,
00837                   "we're not in galley mode");
00838   nsIFrame* lastKidFrame = aKidFrame;
00839 
00840   // Move the frames that follow aKidFrame by aDeltaY 
00841   for (nsIFrame* kidFrame = aKidFrame->GetNextSibling(); kidFrame;
00842        kidFrame = kidFrame->GetNextSibling()) {
00843     // Move the frame if we need to
00844     if (aDeltaY != 0) {
00845       kidFrame->SetPosition(kidFrame->GetPosition() + nsPoint(0, aDeltaY));
00846       nsTableFrame::RePositionViews(kidFrame);
00847     }
00848 
00849     // Remember the last frame
00850     lastKidFrame = kidFrame;
00851   }
00852 
00853   // Update our running y-offset to reflect the bottommost child
00854   aReflowState.y = lastKidFrame->GetRect().YMost();
00855 
00856   return NS_OK;
00857 }
00858 
00859 // Create a continuing frame, add it to the child list, and then push it
00860 // and the frames that follow
00861 void 
00862 nsTableRowGroupFrame::CreateContinuingRowFrame(nsPresContext& aPresContext,
00863                                                nsIFrame&       aRowFrame,
00864                                                nsIFrame**      aContRowFrame)
00865 {
00866   // XXX what is the row index?
00867   if (!aContRowFrame) {NS_ASSERTION(PR_FALSE, "bad call"); return;}
00868   // create the continuing frame which will create continuing cell frames
00869   nsresult rv = aPresContext.PresShell()->FrameConstructor()->
00870     CreateContinuingFrame(&aPresContext, &aRowFrame, this, aContRowFrame);
00871   if (NS_FAILED(rv)) {
00872     *aContRowFrame = nsnull;
00873     return;
00874   }
00875 
00876   // Add the continuing row frame to the child list
00877   nsIFrame* nextRow;
00878   GetNextFrame(&aRowFrame, &nextRow);
00879   (*aContRowFrame)->SetNextSibling(nextRow);
00880   aRowFrame.SetNextSibling(*aContRowFrame);
00881           
00882   // Push the continuing row frame and the frames that follow
00883   PushChildren(&aPresContext, *aContRowFrame, &aRowFrame);
00884 }
00885 
00886 // Reflow the cells with rowspan > 1 which originate between aFirstRow
00887 // and end on or after aLastRow. aFirstTruncatedRow is the highest row on the
00888 // page that contains a cell which cannot split on this page 
00889 void
00890 nsTableRowGroupFrame::SplitSpanningCells(nsPresContext&          aPresContext,
00891                                          const nsHTMLReflowState& aReflowState,
00892                                          nsTableFrame&            aTable,
00893                                          nsTableRowFrame&         aFirstRow, 
00894                                          nsTableRowFrame&         aLastRow,  
00895                                          PRBool                   aFirstRowIsTopOfPage,
00896                                          nscoord                  aAvailHeight,
00897                                          nsTableRowFrame*&        aContRow,
00898                                          nsTableRowFrame*&        aFirstTruncatedRow,
00899                                          nscoord&                 aDesiredHeight)
00900 {
00901   aFirstTruncatedRow = nsnull;
00902   aDesiredHeight     = 0;
00903 
00904   PRInt32 lastRowIndex = aLastRow.GetRowIndex();
00905   PRBool wasLast = PR_FALSE;
00906   // Iterate the rows between aFirstRow and aLastRow
00907   for (nsTableRowFrame* row = &aFirstRow; !wasLast; row = row->GetNextRow()) {
00908     wasLast = (row == &aLastRow);
00909     PRInt32 rowIndex = row->GetRowIndex();
00910     nsPoint rowPos = row->GetPosition();
00911     // Iterate the cells looking for those that have rowspan > 1
00912     for (nsTableCellFrame* cell = row->GetFirstCell(); cell; cell = cell->GetNextCell()) {
00913       PRInt32 rowSpan = aTable.GetEffectiveRowSpan(rowIndex, *cell);
00914       // Only reflow rowspan > 1 cells which span aLastRow. Those which don't span aLastRow
00915       // were reflowed correctly during the unconstrained height reflow. 
00916       if ((rowSpan > 1) && (rowIndex + rowSpan > lastRowIndex)) {
00917         nsReflowStatus status;
00918         // Ask the row to reflow the cell to the height of all the rows it spans up through aLastRow
00919         // aAvailHeight is the space between the row group start and the end of the page
00920         nscoord cellAvailHeight = aAvailHeight - rowPos.y;
00921         nscoord cellHeight = row->ReflowCellFrame(&aPresContext, aReflowState, cell, 
00922                                                   cellAvailHeight, status);
00923         aDesiredHeight = PR_MAX(aDesiredHeight, rowPos.y + cellHeight);
00924         if (NS_FRAME_IS_COMPLETE(status)) {
00925           if (cellHeight > cellAvailHeight) {
00926             aFirstTruncatedRow = row;
00927             if ((row != &aFirstRow) || !aFirstRowIsTopOfPage) {
00928               // return now, since we will be getting another reflow after either (1) row is 
00929               // moved to the next page or (2) the row group is moved to the next page
00930               return;
00931             }
00932           }
00933         }
00934         else {
00935           if (!aContRow) {
00936             CreateContinuingRowFrame(aPresContext, aLastRow, (nsIFrame**)&aContRow);
00937           }
00938           if (aContRow) {
00939             if (row != &aLastRow) {
00940               // aContRow needs a continuation for cell, since cell spanned into aLastRow 
00941               // but does not originate there
00942               nsTableCellFrame* contCell = nsnull;
00943               aPresContext.PresShell()->FrameConstructor()->
00944                 CreateContinuingFrame(&aPresContext, cell, &aLastRow,
00945                                       (nsIFrame**)&contCell);
00946               PRInt32 colIndex;
00947               cell->GetColIndex(colIndex);
00948               aContRow->InsertCellFrame(contCell, colIndex);
00949             }
00950           }
00951         }
00952       }
00953     }
00954   }
00955 }
00956 
00957 // Remove the next-in-flow of the row, its cells and their cell blocks. This 
00958 // is necessary in case the row doesn't need a continuation later on or needs 
00959 // a continuation which doesn't have the same number of cells that now exist. 
00960 void
00961 nsTableRowGroupFrame::UndoContinuedRow(nsPresContext*  aPresContext,
00962                                        nsTableRowFrame* aRow)
00963 {
00964   if (!aRow) return; // allow null aRow to avoid callers doing null checks
00965 
00966   // rowBefore was the prev-sibling of aRow's next-sibling before aRow was created
00967   nsTableRowFrame* rowBefore = (nsTableRowFrame*)aRow->GetPrevInFlow();
00968 
00969   nsIFrame* firstOverflow = GetOverflowFrames(aPresContext, PR_TRUE); 
00970   if (!rowBefore || !firstOverflow || (firstOverflow != aRow)) {
00971     NS_ASSERTION(PR_FALSE, "invalid continued row");
00972     return;
00973   }
00974 
00975   // Remove aRow from the sibling chain and hook its next-sibling up with rowBefore
00976   rowBefore->SetNextSibling(aRow->GetNextSibling());
00977 
00978   // Destroy the row, its cells, and their cell blocks. Cell blocks that have split
00979   // will not have reflowed yet to pick up content from any overflow lines.
00980   aRow->Destroy(aPresContext);
00981 }
00982 
00983 static nsTableRowFrame* 
00984 GetRowBefore(nsTableRowFrame& aStartRow,
00985              nsTableRowFrame& aRow)
00986 {
00987   nsTableRowFrame* rowBefore = nsnull;
00988   for (nsTableRowFrame* sib = &aStartRow; sib && (sib != &aRow); sib = sib->GetNextRow()) {
00989     rowBefore = sib;
00990   }
00991   return rowBefore;
00992 }
00993 
00994 nsresult
00995 nsTableRowGroupFrame::SplitRowGroup(nsPresContext*          aPresContext,
00996                                     nsHTMLReflowMetrics&     aDesiredSize,
00997                                     const nsHTMLReflowState& aReflowState,
00998                                     nsTableFrame*            aTableFrame,
00999                                     nsReflowStatus&          aStatus)
01000 {
01001   NS_PRECONDITION(aPresContext->IsPaginated(), "SplitRowGroup currently supports only paged media");
01002 
01003   nsresult rv = NS_OK;
01004   nsTableRowFrame* prevRowFrame = nsnull;
01005   aDesiredSize.height = 0;
01006 
01007   GET_PIXELS_TO_TWIPS(aPresContext, p2t);
01008   nscoord availWidth  = (NS_UNCONSTRAINEDSIZE == aReflowState.availableWidth) ?
01009                         NS_UNCONSTRAINEDSIZE :
01010                         nsTableFrame::RoundToPixel(aReflowState.availableWidth, p2t);
01011   nscoord availHeight = (NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight) ?
01012                         NS_UNCONSTRAINEDSIZE :
01013                         nsTableFrame::RoundToPixel(aReflowState.availableHeight, p2t);
01014   
01015   PRBool  borderCollapse = ((nsTableFrame*)aTableFrame->GetFirstInFlow())->IsBorderCollapse();
01016   nscoord cellSpacingY   = aTableFrame->GetCellSpacingY();
01017   
01018   // get the page height
01019   nsRect actualRect;
01020   nsRect adjRect;
01021   aPresContext->GetPageDim(&actualRect, &adjRect);
01022   nscoord pageHeight = actualRect.height;
01023 
01024   PRBool isTopOfPage = aReflowState.mFlags.mIsTopOfPage;
01025   nsTableRowFrame* firstRowThisPage = GetFirstRow();
01026 
01027   // Walk each of the row frames looking for the first row frame that doesn't fit 
01028   // in the available space
01029   for (nsTableRowFrame* rowFrame = firstRowThisPage; rowFrame; rowFrame = rowFrame->GetNextRow()) {
01030     PRBool rowIsOnPage = PR_TRUE;
01031     nsRect rowRect = rowFrame->GetRect();
01032     // See if the row fits on this page
01033     if (rowRect.YMost() > availHeight) {
01034       nsTableRowFrame* contRow = nsnull;
01035       // Reflow the row in the availabe space and have it split if it is the 1st
01036       // row (on the page) or there is at least 5% of the current page available 
01037       // XXX this 5% should be made a preference 
01038       if (!prevRowFrame || (availHeight - aDesiredSize.height > pageHeight / 20)) { 
01039         nsSize availSize(availWidth, PR_MAX(availHeight - rowRect.y, 0));
01040         // don't let the available height exceed what CalculateRowHeights set for it
01041         availSize.height = PR_MIN(availSize.height, rowRect.height);
01042 
01043         nsHTMLReflowState rowReflowState(aPresContext, aReflowState, rowFrame, availSize, 
01044                                          eReflowReason_Resize);
01045         InitChildReflowState(*aPresContext, borderCollapse, p2t, rowReflowState);
01046         rowReflowState.mFlags.mIsTopOfPage = isTopOfPage; // set top of page
01047         nsHTMLReflowMetrics rowMetrics(PR_FALSE);
01048 
01049         // Reflow the cell with the constrained height. A cell with rowspan >1 will get this
01050         // reflow later during SplitSpanningCells.
01051         rv = ReflowChild(rowFrame, aPresContext, rowMetrics, rowReflowState,
01052                          0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus);
01053         if (NS_FAILED(rv)) return rv;
01054         rowFrame->SetSize(nsSize(rowMetrics.width, rowMetrics.height));
01055         rowFrame->DidReflow(aPresContext, nsnull, NS_FRAME_REFLOW_FINISHED);
01056         rowFrame->DidResize(aPresContext, aReflowState);
01057 
01058         if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
01059           // The row frame is incomplete and all of the rowspan 1 cells' block frames split
01060           if ((rowMetrics.height <= rowReflowState.availableHeight) || isTopOfPage) {
01061             // The row stays on this page because either it split ok or we're on the top of page.
01062             // If top of page and the height exceeded the avail height, then there will be data loss
01063             NS_WARN_IF_FALSE(rowMetrics.height <= rowReflowState.availableHeight, 
01064                             "data loss - incomplete row needed more height than available, on top of page");
01065             CreateContinuingRowFrame(*aPresContext, *rowFrame, (nsIFrame**)&contRow);
01066             if (contRow) {
01067               aDesiredSize.height += rowMetrics.height;
01068               if (prevRowFrame) 
01069                 aDesiredSize.height += cellSpacingY;
01070             }
01071             else return NS_ERROR_NULL_POINTER;
01072           }
01073           else {
01074             // Put the row on the next page to give it more height 
01075             rowIsOnPage = PR_FALSE;
01076           }
01077         } 
01078         else {
01079           // The row frame is complete because either (1) it's minimum height is greater than the 
01080           // available height we gave it, or (2) it may have been given a larger height through 
01081           // style than it's content, or (3) it contains a rowspan >1 cell which hasn't been
01082           // reflowed with a constrained height yet (we will find out when SplitSpanningCells is
01083           // called below)
01084           if (rowMetrics.height >= availSize.height) {
01085             // cases (1) and (2)
01086             if (isTopOfPage) { 
01087               // We're on top of the page, so keep the row on this page. There will be data loss.
01088               // Push the row frame that follows
01089               nsTableRowFrame* nextRowFrame = rowFrame->GetNextRow();
01090               if (nextRowFrame) {
01091                 aStatus = NS_FRAME_NOT_COMPLETE;
01092               }
01093               aDesiredSize.height += rowMetrics.height;
01094               if (prevRowFrame) 
01095                 aDesiredSize.height += cellSpacingY;
01096               NS_WARNING("data loss - complete row needed more height than available, on top of page");
01097             }
01098             else {  
01099               // We're not on top of the page, so put the row on the next page to give it more height 
01100               rowIsOnPage = PR_FALSE;
01101             }
01102           }
01103         }
01104       } //if (!prevRowFrame || (availHeight - aDesiredSize.height > pageHeight / 20))
01105       else { 
01106         // put the row on the next page to give it more height
01107         rowIsOnPage = PR_FALSE;
01108       }
01109 
01110       nsTableRowFrame* lastRowThisPage = rowFrame;
01111       if (!rowIsOnPage) {
01112         if (prevRowFrame) {
01113           availHeight -= prevRowFrame->GetRect().YMost();
01114           lastRowThisPage = prevRowFrame;
01115           isTopOfPage = (lastRowThisPage == firstRowThisPage) && aReflowState.mFlags.mIsTopOfPage;
01116           aStatus = NS_FRAME_NOT_COMPLETE;
01117         }
01118         else {
01119           // We can't push children, so let our parent reflow us again with more space
01120           aDesiredSize.height = rowRect.YMost();
01121           break;
01122         }
01123       }
01124       // reflow the cells with rowspan >1 that occur on the page
01125 
01126       nsTableRowFrame* firstTruncatedRow;
01127       nscoord yMost;
01128       SplitSpanningCells(*aPresContext, aReflowState, *aTableFrame, *firstRowThisPage,
01129                          *lastRowThisPage, aReflowState.mFlags.mIsTopOfPage, availHeight, contRow, 
01130                          firstTruncatedRow, yMost);
01131       if (firstTruncatedRow) {
01132         // A rowspan >1 cell did not fit (and could not split) in the space we gave it
01133         if (firstTruncatedRow == firstRowThisPage) {
01134           if (aReflowState.mFlags.mIsTopOfPage) {
01135             NS_WARNING("data loss in a row spanned cell");
01136           }
01137           else {
01138             // We can't push children, so let our parent reflow us again with more space
01139             aDesiredSize.height = rowRect.YMost();
01140             aStatus = NS_FRAME_COMPLETE;
01141             UndoContinuedRow(aPresContext, contRow);
01142             contRow = nsnull;
01143           }
01144         }
01145         else { // (firstTruncatedRow != firstRowThisPage)
01146           // Try to put firstTruncateRow on the next page 
01147           nsTableRowFrame* rowBefore = ::GetRowBefore(*firstRowThisPage, *firstTruncatedRow);
01148           availHeight -= rowBefore->GetRect().YMost();
01149 
01150           UndoContinuedRow(aPresContext, contRow);
01151           contRow = nsnull;
01152           nsTableRowFrame* oldLastRowThisPage = lastRowThisPage;
01153           lastRowThisPage = firstTruncatedRow;
01154           aStatus = NS_FRAME_NOT_COMPLETE;
01155 
01156           // Call SplitSpanningCells again with rowBefore as the last row on the page
01157           SplitSpanningCells(*aPresContext, aReflowState, *aTableFrame, 
01158                              *firstRowThisPage, *rowBefore, aReflowState.mFlags.mIsTopOfPage, 
01159                              availHeight, contRow, firstTruncatedRow, aDesiredSize.height);
01160           if (firstTruncatedRow) {
01161             if (aReflowState.mFlags.mIsTopOfPage) {
01162               // We were better off with the 1st call to SplitSpanningCells, do it again
01163               UndoContinuedRow(aPresContext, contRow);
01164               contRow = nsnull;
01165               lastRowThisPage = oldLastRowThisPage;
01166               SplitSpanningCells(*aPresContext, aReflowState, *aTableFrame, *firstRowThisPage,
01167                                  *lastRowThisPage, aReflowState.mFlags.mIsTopOfPage, availHeight, contRow, 
01168                                  firstTruncatedRow, aDesiredSize.height);
01169               NS_WARNING("data loss in a row spanned cell");
01170             }
01171             else {
01172               // Let our parent reflow us again with more space
01173               aDesiredSize.height = rowRect.YMost();
01174               aStatus = NS_FRAME_COMPLETE;
01175               UndoContinuedRow(aPresContext, contRow);
01176               contRow = nsnull;
01177             }
01178           }
01179         } // if (firstTruncatedRow == firstRowThisPage)
01180       } // if (firstTruncatedRow)
01181       else {
01182         aDesiredSize.height = PR_MAX(aDesiredSize.height, yMost);
01183         if (contRow) {
01184           aStatus = NS_FRAME_NOT_COMPLETE;
01185         }
01186       }
01187       if (NS_FRAME_IS_NOT_COMPLETE(aStatus) && !contRow) {
01188         nsTableRowFrame* nextRow = lastRowThisPage->GetNextRow();
01189         if (nextRow) {
01190           PushChildren(aPresContext, nextRow, lastRowThisPage);
01191         }
01192       }
01193       break;
01194     } // if (rowRect.YMost() > availHeight)
01195     else { 
01196       aDesiredSize.height = rowRect.YMost();
01197       prevRowFrame = rowFrame;
01198       // see if there is a page break after the row
01199       nsTableRowFrame* nextRow = rowFrame->GetNextRow();
01200       if (nextRow && nsTableFrame::PageBreakAfter(*rowFrame, nextRow)) {
01201         PushChildren(aPresContext, nextRow, rowFrame);
01202         aStatus = NS_FRAME_NOT_COMPLETE;
01203         break;
01204       }
01205     }
01206     isTopOfPage = PR_FALSE; // after the 1st row, we can't be on top of the page any more.
01207   }
01208   return NS_OK;
01209 }
01210 
01215 NS_METHOD
01216 nsTableRowGroupFrame::Reflow(nsPresContext*          aPresContext,
01217                              nsHTMLReflowMetrics&     aDesiredSize,
01218                              const nsHTMLReflowState& aReflowState,
01219                              nsReflowStatus&          aStatus)
01220 {
01221   DO_GLOBAL_REFLOW_COUNT("nsTableRowGroupFrame", aReflowState.reason);
01222   DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
01223 #if defined DEBUG_TABLE_REFLOW_TIMING
01224   nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState);
01225 #endif
01226 
01227   nsresult rv = NS_OK;
01228   aStatus     = NS_FRAME_COMPLETE;
01229         
01230   PRBool isPaginated = aPresContext->IsPaginated();
01231 
01232   nsTableFrame* tableFrame = nsnull;
01233   rv = nsTableFrame::GetTableFrame(this, tableFrame);
01234   if (!tableFrame) return NS_ERROR_NULL_POINTER;
01235 
01236   // see if a special height reflow needs to occur due to having a pct height
01237   if (!NeedSpecialReflow()) 
01238     nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState);
01239 
01240   nsRowGroupReflowState state(aReflowState, tableFrame);
01241   PRBool haveDesiredHeight = PR_FALSE;
01242   const nsStyleVisibility* groupVis = GetStyleVisibility();
01243   PRBool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE == groupVis->mVisible);
01244   if (collapseGroup) {
01245     tableFrame->SetNeedToCollapseRows(PR_TRUE);
01246   }
01247 
01248   if (eReflowReason_Incremental == aReflowState.reason) {
01249     rv = IncrementalReflow(aPresContext, aDesiredSize, state, aStatus);
01250   } 
01251   else { 
01252     // Check for an overflow list
01253     MoveOverflowToChildList(aPresContext);
01254   
01255     // Reflow the existing frames. 
01256     PRBool splitDueToPageBreak = PR_FALSE;
01257     rv = ReflowChildren(aPresContext, aDesiredSize, state, aStatus,
01258                         nsnull, PR_FALSE, nsnull, &splitDueToPageBreak);
01259   
01260     // Return our desired rect
01261     aDesiredSize.width = aReflowState.availableWidth;
01262     aDesiredSize.height = state.y;
01263 
01264     // shrink wrap rows to height of tallest cell in that row
01265     PRBool isTableUnconstrainedReflow = 
01266       (NS_UNCONSTRAINEDSIZE == aReflowState.parentReflowState->availableWidth);
01267 
01268     // Avoid calling CalculateRowHeights. We can avoid it if the table is going to be
01269     // doing a pass 2 reflow. In the case where the table is getting an unconstrained
01270     // reflow, then we need to do this because the table will skip the pass 2 reflow,
01271     // but we need to correctly calculate the row group height and we can't if there
01272     // are row spans unless we do this step
01273     if (aReflowState.mFlags.mSpecialHeightReflow) {
01274       DidResizeRows(*aPresContext, aReflowState, aDesiredSize);
01275       if (isPaginated) {
01276         CacheRowHeightsForPrinting(aPresContext, GetFirstRow());
01277       }
01278     }
01279     else if ((eReflowReason_Initial != aReflowState.reason) || 
01280              isTableUnconstrainedReflow                     ||
01281              isPaginated) {
01282       CalculateRowHeights(aPresContext, aDesiredSize, aReflowState);
01283       haveDesiredHeight = PR_TRUE;
01284     }
01285 
01286     // See if all the frames fit. Do not try to split anything if we're
01287     // not paginated ... we can't split across columns yet.
01288     if (aPresContext->IsPaginated() &&
01289         (NS_FRAME_NOT_COMPLETE == aStatus || splitDueToPageBreak || 
01290          aDesiredSize.height > aReflowState.availableHeight)) {
01291       // Nope, find a place to split the row group 
01292       PRBool specialReflow = (PRBool)aReflowState.mFlags.mSpecialHeightReflow;
01293       ((nsHTMLReflowState::ReflowStateFlags&)aReflowState.mFlags).mSpecialHeightReflow = PR_FALSE;
01294 
01295       SplitRowGroup(aPresContext, aDesiredSize, aReflowState, tableFrame, aStatus);
01296 
01297       ((nsHTMLReflowState::ReflowStateFlags&)aReflowState.mFlags).mSpecialHeightReflow = specialReflow;
01298     }
01299   }
01300   SetHasStyleHeight((NS_UNCONSTRAINEDSIZE != aReflowState.mComputedHeight) &&
01301                     (aReflowState.mComputedHeight > 0)); 
01302   
01303   if (aReflowState.mFlags.mSpecialHeightReflow) {
01304     SetNeedSpecialReflow(PR_FALSE);
01305   }
01306 
01307   // just set our width to what was available. The table will calculate the width and not use our value.
01308   aDesiredSize.width = aReflowState.availableWidth;
01309   if (!haveDesiredHeight) {
01310     // calculate the height based on the rect of the last row
01311     aDesiredSize.height = GetHeightOfRows();
01312   }
01313   // if we have a nextinflow we are not complete
01314   if (GetNextInFlow()) {
01315     aStatus |= NS_FRAME_NOT_COMPLETE;
01316   }
01317   aDesiredSize.mOverflowArea.UnionRect(aDesiredSize.mOverflowArea, nsRect(0, 0, aDesiredSize.width,
01318                                                                              aDesiredSize.height)); 
01319   FinishAndStoreOverflow(&aDesiredSize);
01320 #if defined DEBUG_TABLE_REFLOW_TIMING
01321   nsTableFrame::DebugReflow(this, (nsHTMLReflowState&)aReflowState, &aDesiredSize, aStatus);
01322 #endif
01323   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
01324   return rv;
01325 }
01326 
01327 
01328 NS_METHOD 
01329 nsTableRowGroupFrame::IncrementalReflow(nsPresContext*        aPresContext,
01330                                         nsHTMLReflowMetrics&   aDesiredSize,
01331                                         nsRowGroupReflowState& aReflowState,
01332                                         nsReflowStatus&        aStatus)
01333 {
01334   // the row group is a target if its path has a reflow command
01335   nsHTMLReflowCommand* command = aReflowState.reflowState.path->mReflowCommand;
01336   if (command)
01337     IR_TargetIsMe(aPresContext, aDesiredSize, aReflowState, aStatus);
01338 
01339   // see if the chidren are targets as well
01340   // XXXwaterson Note that this will cause us to RecoverState (which
01341   // is O(n) in the number of child rows) once for each reflow
01342   // target. It'd probably be better to invert the loops; i.e., walk
01343   // the rows, checking each to see if it's an IR target (which could
01344   // be done in O(1) if we do hashing in the reflow path).
01345   nsReflowPath::iterator iter = aReflowState.reflowState.path->FirstChild();
01346   nsReflowPath::iterator end = aReflowState.reflowState.path->EndChildren();
01347   for (; iter != end; ++iter)
01348     IR_TargetIsChild(aPresContext, aDesiredSize, aReflowState, aStatus, *iter);
01349 
01350   return NS_OK;
01351 }
01352 
01353 NS_IMETHODIMP
01354 nsTableRowGroupFrame::AppendFrames(nsIAtom*        aListName,
01355                                    nsIFrame*       aFrameList)
01356 {
01357   // collect the new row frames in an array
01358   nsAutoVoidArray rows;
01359   for (nsIFrame* rowFrame = aFrameList; rowFrame;
01360        rowFrame = rowFrame->GetNextSibling()) {
01361     if (nsLayoutAtoms::tableRowFrame == rowFrame->GetType()) {
01362       rows.AppendElement(rowFrame);
01363     }
01364   }
01365 
01366   PRInt32 rowIndex = GetRowCount();
01367   // Append the frames to the sibling chain
01368   mFrames.AppendFrames(nsnull, aFrameList);
01369 
01370   if (rows.Count() > 0) {
01371     nsTableFrame* tableFrame = nsnull;
01372     nsTableFrame::GetTableFrame(this, tableFrame);
01373     if (tableFrame) {
01374       tableFrame->AppendRows(*this, rowIndex, rows);
01375       // Reflow the new frames. They're already marked dirty, so generate a reflow
01376       // command that tells us to reflow our dirty child frames
01377       nsTableFrame::AppendDirtyReflowCommand(this);
01378       if (tableFrame->RowIsSpannedInto(rowIndex)) {
01379         tableFrame->SetNeedStrategyInit(PR_TRUE);
01380       }
01381       else if (!tableFrame->IsAutoHeight()) {
01382         // The table isn't auto height, so any previously reflowed rows
01383         // it contains were already adjusted so that they take up all of
01384         // the table's height. We need to trigger a strategy balance to
01385         // ensure that all rows are resized properly during the dirty reflow we
01386         // generated above.
01387 
01388         tableFrame->SetNeedStrategyBalance(PR_TRUE);
01389       }
01390     }
01391   }
01392 
01393   return NS_OK;
01394 }
01395 
01396 NS_IMETHODIMP
01397 nsTableRowGroupFrame::InsertFrames(nsIAtom*        aListName,
01398                                    nsIFrame*       aPrevFrame,
01399                                    nsIFrame*       aFrameList)
01400 {
01401   nsTableFrame* tableFrame = nsnull;
01402   nsTableFrame::GetTableFrame(this, tableFrame);
01403   if (!tableFrame) {
01404     NS_ASSERTION(PR_FALSE, "no table frame");
01405     return NS_ERROR_NULL_POINTER;
01406   }
01407   // collect the new row frames in an array
01408   nsVoidArray rows;
01409   PRBool gotFirstRow = PR_FALSE;
01410   for (nsIFrame* rowFrame = aFrameList; rowFrame;
01411        rowFrame = rowFrame->GetNextSibling()) {
01412     if (nsLayoutAtoms::tableRowFrame == rowFrame->GetType()) {
01413       rows.AppendElement(rowFrame);
01414       if (!gotFirstRow) {
01415         ((nsTableRowFrame*)rowFrame)->SetFirstInserted(PR_TRUE);
01416         gotFirstRow = PR_TRUE;
01417         tableFrame->SetRowInserted(PR_TRUE);
01418       }
01419     }
01420   }
01421 
01422   PRInt32 startRowIndex = GetStartRowIndex();
01423   // Insert the frames in the sibling chain
01424   mFrames.InsertFrames(nsnull, aPrevFrame, aFrameList);
01425 
01426   PRInt32 numRows = rows.Count();
01427   if (numRows > 0) {
01428     nsTableRowFrame* prevRow = (nsTableRowFrame *)nsTableFrame::GetFrameAtOrBefore(this, aPrevFrame, nsLayoutAtoms::tableRowFrame);
01429     PRInt32 rowIndex = (prevRow) ? prevRow->GetRowIndex() + 1 : startRowIndex;
01430     tableFrame->InsertRows(*this, rows, rowIndex, PR_TRUE);
01431 
01432     // Reflow the new frames. They're already marked dirty, so generate a reflow
01433     // command that tells us to reflow our dirty child frames
01434     nsTableFrame::AppendDirtyReflowCommand(this);
01435     if (tableFrame->RowIsSpannedInto(rowIndex) || 
01436         tableFrame->RowHasSpanningCells(rowIndex + numRows - 1)) {
01437       tableFrame->SetNeedStrategyInit(PR_TRUE);
01438     }
01439     else if (!tableFrame->IsAutoHeight()) {
01440       // The table isn't auto height, so any previously reflowed rows
01441       // it contains were already adjusted so that they take up all of
01442       // the table's height. We need to trigger a strategy balance to
01443       // ensure that all rows are resized properly during the dirty reflow we
01444       // generated above.
01445 
01446       tableFrame->SetNeedStrategyBalance(PR_TRUE);
01447     }
01448   }
01449   return NS_OK;
01450 }
01451 
01452 NS_IMETHODIMP
01453 nsTableRowGroupFrame::RemoveFrame(nsIAtom*        aListName,
01454                                   nsIFrame*       aOldFrame)
01455 {
01456   nsTableFrame* tableFrame = nsnull;
01457   nsTableFrame::GetTableFrame(this, tableFrame);
01458   if (tableFrame) {
01459     if (nsLayoutAtoms::tableRowFrame == aOldFrame->GetType()) {
01460       // remove the rows from the table (and flag a rebalance)
01461       tableFrame->RemoveRows((nsTableRowFrame &)*aOldFrame, 1, PR_TRUE);
01462 
01463       // XXX this could be optimized (see nsTableFrame::RemoveRows)
01464       tableFrame->SetNeedStrategyInit(PR_TRUE);
01465       // Because we haven't added any new frames we don't need to do a pass1
01466       // reflow. Just generate a reflow command so we reflow the table 
01467       nsTableFrame::AppendDirtyReflowCommand(this);
01468     }
01469   }
01470   mFrames.DestroyFrame(GetPresContext(), aOldFrame);
01471 
01472   return NS_OK;
01473 }
01474 
01475 NS_METHOD 
01476 nsTableRowGroupFrame::IR_TargetIsMe(nsPresContext*        aPresContext,
01477                                     nsHTMLReflowMetrics&   aDesiredSize,
01478                                     nsRowGroupReflowState& aReflowState,
01479                                     nsReflowStatus&        aStatus)
01480 {
01481   nsresult rv = NS_FRAME_COMPLETE;
01482   nsReflowType type;
01483   aReflowState.reflowState.path->mReflowCommand->GetType(type);
01484 
01485   switch (type) {
01486     case eReflowType_ReflowDirty: {
01487       nsRowGroupReflowState state(aReflowState);
01488       state.reason = eReflowReason_Resize;
01489       // Reflow the dirty child frames. Typically this is newly added frames.
01490       nsTableRowFrame* firstRowReflowed;
01491       rv = ReflowChildren(aPresContext, aDesiredSize, state, aStatus,
01492                           nsnull, PR_TRUE, &firstRowReflowed);
01493       CalculateRowHeights(aPresContext, aDesiredSize, aReflowState.reflowState, firstRowReflowed);
01494       break;
01495     }
01496     case eReflowType_StyleChanged :
01497       rv = IR_StyleChanged(aPresContext, aDesiredSize, aReflowState, aStatus);
01498       break;
01499     case eReflowType_ContentChanged :
01500       NS_ASSERTION(PR_FALSE, "illegal reflow type: ContentChanged");
01501       rv = NS_ERROR_ILLEGAL_VALUE;
01502       break; 
01503     default:
01504       NS_NOTYETIMPLEMENTED("unexpected reflow command type");
01505       rv = NS_ERROR_NOT_IMPLEMENTED;
01506       break;
01507   }
01508 
01509   return rv;
01510 }
01511 
01512 nscoord 
01513 nsTableRowGroupFrame::GetHeightBasis(const nsHTMLReflowState& aReflowState)
01514 {
01515   nscoord result = 0;
01516   nsTableFrame* tableFrame = nsnull;
01517   nsTableFrame::GetTableFrame((nsIFrame*)this, tableFrame);
01518   if (tableFrame) {
01519     if ((aReflowState.mComputedHeight > 0) && (aReflowState.mComputedHeight < NS_UNCONSTRAINEDSIZE)) {
01520       nscoord cellSpacing = PR_MAX(0, GetRowCount() - 1) * tableFrame->GetCellSpacingY();
01521       result = aReflowState.mComputedHeight - cellSpacing;
01522     }
01523     else {
01524       const nsHTMLReflowState* parentRS = aReflowState.parentReflowState;
01525       if (parentRS && (tableFrame != parentRS->frame)) {
01526         parentRS = parentRS->parentReflowState;
01527       }
01528       if (parentRS && (tableFrame == parentRS->frame) && 
01529           (parentRS->mComputedHeight > 0) && (parentRS->mComputedHeight < NS_UNCONSTRAINEDSIZE)) {
01530         nscoord cellSpacing = PR_MAX(0, tableFrame->GetRowCount() + 1) * tableFrame->GetCellSpacingY();
01531         result = parentRS->mComputedHeight - cellSpacing;
01532       }
01533     }
01534   }
01535 
01536   return result;
01537 }
01538 
01539 nscoord 
01540 nsTableRowGroupFrame::GetHeightOfRows()
01541 {
01542   nsTableFrame* tableFrame = nsnull;
01543   nsTableFrame::GetTableFrame(this, tableFrame);
01544   if (!tableFrame) return 0;
01545 
01546   nscoord height = 0;
01547 
01548   // enumerate the rows and total their heights
01549   nsIFrame* rowFrame = GetFirstChild(nsnull);
01550   PRInt32 numRows = 0;
01551   while (rowFrame) {
01552     if (NS_STYLE_DISPLAY_TABLE_ROW == rowFrame->GetStyleDisplay()->mDisplay) {
01553       height += rowFrame->GetSize().height;
01554       numRows++;
01555     }
01556     GetNextFrame(rowFrame, &rowFrame);
01557   }
01558   if (numRows > 1) {
01559     height += (numRows - 1) * tableFrame->GetCellSpacingY(); // add in cell spacing
01560   }
01561 
01562   return height;
01563 }
01564 
01565 // Recovers the reflow state to what it should be if aKidFrame is about
01566 // to be reflowed. Restores availSize, y
01567 nsresult
01568 nsTableRowGroupFrame::RecoverState(nsRowGroupReflowState& aReflowState,
01569                                    nsIFrame*              aKidFrame)
01570 {
01571   nsTableFrame* tableFrame = nsnull;
01572   nsTableFrame::GetTableFrame(this, tableFrame);
01573   nscoord cellSpacingY = tableFrame->GetCellSpacingY();
01574 
01575   aReflowState.y = 0;
01576 
01577   // Walk the list of children up to aKidFrame
01578   for (nsIFrame* frame = mFrames.FirstChild(); frame && (frame != aKidFrame);
01579        frame = frame->GetNextSibling()) {
01580     if (frame->GetType() == nsLayoutAtoms::tableRowFrame) {
01581       // Update the running y-offset
01582       nsSize kidSize = frame->GetSize();
01583       aReflowState.y += kidSize.height + cellSpacingY;
01584 
01585       // If our height is constrained then update the available height
01586       if (NS_UNCONSTRAINEDSIZE != aReflowState.availSize.height) {
01587         aReflowState.availSize.height -= kidSize.height;
01588       }
01589     }
01590   }
01591 
01592   return NS_OK;
01593 }
01594 
01595 PRBool
01596 nsTableRowGroupFrame::IsSimpleRowFrame(nsTableFrame* aTableFrame,
01597                                        nsIFrame*     aFrame)
01598 {
01599   // Make sure it's a row frame and not a row group frame
01600   if (aFrame->GetType() == nsLayoutAtoms::tableRowFrame) {
01601     PRInt32 rowIndex = ((nsTableRowFrame*)aFrame)->GetRowIndex();
01602     
01603     // It's a simple row frame if there are no cells that span into or
01604     // across the row
01605     if (!aTableFrame->RowIsSpannedInto(rowIndex) &&
01606         !aTableFrame->RowHasSpanningCells(rowIndex)) {
01607       return PR_TRUE;
01608     }
01609   }
01610 
01611   return PR_FALSE;
01612 }
01613 
01614 nsIFrame*
01615 GetLastRowSibling(nsIFrame* aRowFrame)
01616 {
01617   nsIFrame* lastRowFrame = nsnull;
01618   for (nsIFrame* lastFrame = aRowFrame; lastFrame;
01619        lastFrame = lastFrame->GetNextSibling()) {
01620     if (nsLayoutAtoms::tableRowFrame == lastFrame->GetType()) {
01621       lastRowFrame = lastFrame;
01622     }
01623   }
01624   return lastRowFrame;
01625 }
01626 
01627 NS_METHOD 
01628 nsTableRowGroupFrame::IR_TargetIsChild(nsPresContext*        aPresContext,
01629                                        nsHTMLReflowMetrics&   aDesiredSize,
01630                                        nsRowGroupReflowState& aReflowState,
01631                                        nsReflowStatus&        aStatus,
01632                                        nsIFrame*              aNextFrame)
01633 
01634 {
01635   nsresult rv;
01636   
01637   nsTableFrame* tableFrame = nsnull; 
01638   nsTableFrame::GetTableFrame(this, tableFrame); if (!tableFrame) ABORT1(NS_ERROR_NULL_POINTER);
01639   GET_PIXELS_TO_TWIPS(aPresContext, p2t);
01640 
01641   // Recover the state as if aNextFrame is about to be reflowed
01642   RecoverState(aReflowState, aNextFrame);
01643 
01644   // Remember the old rect
01645   nsSize oldKidSize = aNextFrame->GetSize();
01646 
01647   // Reflow the child giving it as much room as it wants. We'll deal with
01648   // splitting later after final determination of rows heights taking into
01649   // account cells with row spans...
01650   nsSize            kidAvailSize(aReflowState.availSize.width, NS_UNCONSTRAINEDSIZE);
01651   nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState, aNextFrame, 
01652                                    kidAvailSize, aReflowState.reason);
01653   InitChildReflowState(*aPresContext, tableFrame->IsBorderCollapse(), p2t, kidReflowState);
01654 
01655   nsHTMLReflowMetrics desiredSize(aDesiredSize.mComputeMEW,
01656                                   aDesiredSize.mFlags);
01657 
01658   // Pass along the reflow command
01659   rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState,
01660                    0, aReflowState.y, 0, aStatus);
01661 
01662   // Place the row frame
01663   nsRect  kidRect(0, aReflowState.y, desiredSize.width, desiredSize.height);
01664   PlaceChild(aPresContext, aReflowState, aNextFrame, desiredSize);
01665 
01666   // See if the table needs a reflow (e.g., if the column widths have
01667   // changed). If so, just return and don't bother adjusting the rows
01668   // that follow
01669   if (!aReflowState.tableFrame->NeedsReflow(aReflowState.reflowState)) {
01670     // Only call CalculateRowHeights() if necessary since it can be expensive
01671     PRBool needToCalcRowHeights = PR_FALSE; 
01672     if (IsSimpleRowFrame(aReflowState.tableFrame, aNextFrame)) {
01673       // See if the row changed height
01674       if (oldKidSize.height == desiredSize.height) {
01675         // We don't need to do any painting. The row frame has made sure that
01676         // the cell is properly positioned, and done any necessary repainting.
01677         // Just calculate our desired height
01678         aDesiredSize.height = GetLastRowSibling(mFrames.FirstChild())->GetRect().YMost();
01679       } else {
01680         // Inform the row of its new height.
01681         ((nsTableRowFrame*)aNextFrame)->DidResize(aPresContext, aReflowState.reflowState);
01682         // the overflow area may have changed inflate the overflow area
01683         if (aReflowState.tableFrame->IsAutoHeight()) {
01684           // Because other cells in the row may need to be be aligned differently,
01685           // repaint the entire row
01686           // XXX Improve this so the row knows it should bitblt (or repaint) those
01687           // cells that change position...
01688           Invalidate(kidRect);
01689           
01690           // Invalidate the area we're offseting. Note that we only repaint within
01691           // our existing frame bounds.
01692           // XXX It would be better to bitblt the row frames and not repaint,
01693           // but we don't have such a view manager function yet...
01694           if (kidRect.YMost() < mRect.height) {
01695             nsRect  dirtyRect(0, kidRect.YMost(),
01696                               mRect.width, mRect.height - kidRect.YMost());
01697             Invalidate(dirtyRect);
01698           }
01699 
01700           // Adjust the frames that follow
01701           AdjustSiblingsAfterReflow(aReflowState, aNextFrame,
01702                                     desiredSize.height - oldKidSize.height);
01703           aDesiredSize.height = aReflowState.y;
01704         }
01705         else needToCalcRowHeights = PR_TRUE;
01706       }
01707     } else {
01708       if (desiredSize.mNothingChanged) { // mNothingChanges currently only works when a cell is the target
01709         // the cell frame did not change size. Just calculate our desired height
01710         aDesiredSize.height = GetLastRowSibling(mFrames.FirstChild())->GetRect().YMost();
01711       } 
01712       else needToCalcRowHeights = PR_TRUE;
01713     }
01714     if (needToCalcRowHeights) {
01715       // Adjust the frames that follow... 
01716       // XXX is this needed since CalculateRowHeights will be called?
01717       //AdjustSiblingsAfterReflow(aPresContext, aReflowState, aNextFrame,
01718       //                          desiredSize.height - oldKidSize.height);
01719     
01720       // Now recalculate the row heights
01721       CalculateRowHeights(aPresContext, aDesiredSize, aReflowState.reflowState);
01722       
01723       // Because we don't know what changed repaint everything.
01724       // XXX We should change CalculateRowHeights() to return the bounding
01725       // rect of what changed. Or whether anything moved or changed size...
01726       nsRect  dirtyRect(0, 0, mRect.width, mRect.height);
01727       Invalidate(dirtyRect);
01728     }
01729     else {
01730       // need to recover the  OverflowArea
01731       for (nsTableRowFrame* rowFrame = GetFirstRow(); rowFrame; rowFrame = rowFrame->GetNextRow()) {
01732         ConsiderChildOverflow(aDesiredSize.mOverflowArea, rowFrame);
01733       }
01734       FinishAndStoreOverflow(&aDesiredSize);
01735     }
01736   }
01737   
01738   // Return our desired width
01739   //aDesiredSize.width = aReflowState.reflowState.availableWidth;
01740 
01741   return rv;
01742 }
01743 
01744 NS_METHOD 
01745 nsTableRowGroupFrame::IR_StyleChanged(nsPresContext*        aPresContext,
01746                                       nsHTMLReflowMetrics&   aDesiredSize,
01747                                       nsRowGroupReflowState& aReflowState,
01748                                       nsReflowStatus&        aStatus)
01749 {
01750   nsresult rv = NS_OK;
01751   // we presume that all the easy optimizations were done in the nsHTMLStyleSheet before we were called here
01752   // XXX: we can optimize this when we know which style attribute changed
01753   aReflowState.tableFrame->SetNeedStrategyInit(PR_TRUE);
01754   nsRowGroupReflowState state(aReflowState);
01755   nsTableRowFrame* firstRowReflowed;
01756   rv = ReflowChildren(aPresContext, aDesiredSize, state, aStatus,
01757                           nsnull, PR_FALSE, &firstRowReflowed);
01758   CalculateRowHeights(aPresContext, aDesiredSize, aReflowState.reflowState, firstRowReflowed);
01759       
01760   return rv;
01761 }
01762 
01763 nsIAtom*
01764 nsTableRowGroupFrame::GetType() const
01765 {
01766   return nsLayoutAtoms::tableRowGroupFrame;
01767 }
01768 
01769 
01770 /* ----- global methods ----- */
01771 
01772 nsresult 
01773 NS_NewTableRowGroupFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
01774 {
01775   NS_PRECONDITION(aNewFrame, "null OUT ptr");
01776   if (nsnull == aNewFrame) {
01777     return NS_ERROR_NULL_POINTER;
01778   }
01779   nsTableRowGroupFrame* it = new (aPresShell) nsTableRowGroupFrame;
01780   if (nsnull == it) {
01781     return NS_ERROR_OUT_OF_MEMORY;
01782   }
01783   *aNewFrame = it;
01784   return NS_OK;
01785 }
01786 
01787 NS_IMETHODIMP
01788 nsTableRowGroupFrame::Init(nsPresContext*  aPresContext,
01789                            nsIContent*      aContent,
01790                            nsIFrame*        aParent,
01791                            nsStyleContext*  aContext,
01792                            nsIFrame*        aPrevInFlow)
01793 {
01794   nsresult  rv;
01795 
01796   // Let the base class do its processing
01797   rv = nsHTMLContainerFrame::Init(aPresContext, aContent, aParent, aContext,
01798                                   aPrevInFlow);
01799 
01800   // record that children that are ignorable whitespace should be excluded 
01801   mState |= NS_FRAME_EXCLUDE_IGNORABLE_WHITESPACE;
01802 
01803   return rv;
01804 }
01805 
01806 #ifdef DEBUG
01807 NS_IMETHODIMP
01808 nsTableRowGroupFrame::GetFrameName(nsAString& aResult) const
01809 {
01810   return MakeFrameName(NS_LITERAL_STRING("TableRowGroup"), aResult);
01811 }
01812 #endif
01813 
01814 nsMargin* 
01815 nsTableRowGroupFrame::GetBCBorderWidth(float     aPixelsToTwips,
01816                                        nsMargin& aBorder)
01817 {
01818   aBorder.left = aBorder.right = 0;
01819 
01820   nsTableRowFrame* firstRowFrame = nsnull;
01821   nsTableRowFrame* lastRowFrame = nsnull;
01822   for (nsTableRowFrame* rowFrame = GetFirstRow(); rowFrame; rowFrame = rowFrame->GetNextRow()) {
01823     if (!firstRowFrame) {
01824       firstRowFrame = rowFrame;
01825     }
01826     lastRowFrame = rowFrame;
01827   }
01828   if (firstRowFrame) {
01829     aBorder.top    = firstRowFrame->GetTopBCBorderWidth(&aPixelsToTwips);
01830     aBorder.bottom = lastRowFrame->GetBottomBCBorderWidth(&aPixelsToTwips);
01831   }
01832 
01833   return &aBorder;
01834 }
01835 
01836 void nsTableRowGroupFrame::SetContinuousBCBorderWidth(PRUint8     aForSide,
01837                                                       BCPixelSize aPixelValue)
01838 {
01839   switch (aForSide) {
01840     case NS_SIDE_RIGHT:
01841       mRightContBorderWidth = aPixelValue;
01842       return;
01843     case NS_SIDE_BOTTOM:
01844       mBottomContBorderWidth = aPixelValue;
01845       return;
01846     case NS_SIDE_LEFT:
01847       mLeftContBorderWidth = aPixelValue;
01848       return;
01849     default:
01850       NS_ERROR("invalid NS_SIDE argument");
01851   }
01852 }
01853 
01854 //nsILineIterator methods for nsTableFrame
01855 NS_IMETHODIMP
01856 nsTableRowGroupFrame::GetNumLines(PRInt32* aResult)
01857 {
01858   NS_ENSURE_ARG_POINTER(aResult);
01859   *aResult = GetRowCount();
01860   return *aResult; // XXX should return NS_OK
01861 }
01862 
01863 NS_IMETHODIMP
01864 nsTableRowGroupFrame::GetDirection(PRBool* aIsRightToLeft)
01865 {
01866   NS_ENSURE_ARG_POINTER(aIsRightToLeft);
01867   *aIsRightToLeft = PR_FALSE;
01868   return NS_OK;
01869 }
01870   
01871 NS_IMETHODIMP
01872 nsTableRowGroupFrame::GetLine(PRInt32    aLineNumber, 
01873                               nsIFrame** aFirstFrameOnLine, 
01874                               PRInt32*   aNumFramesOnLine,
01875                               nsRect&    aLineBounds, 
01876                               PRUint32*  aLineFlags)
01877 {
01878   NS_ENSURE_ARG_POINTER(aFirstFrameOnLine);
01879   NS_ENSURE_ARG_POINTER(aNumFramesOnLine);
01880   NS_ENSURE_ARG_POINTER(aLineFlags);
01881 
01882   nsTableFrame* parentFrame = nsnull; 
01883   if (NS_FAILED(nsTableFrame::GetTableFrame(this, parentFrame)))
01884     return NS_ERROR_FAILURE;
01885 
01886   nsTableCellMap* cellMap = parentFrame->GetCellMap();
01887   if (!cellMap)
01888      return NS_ERROR_FAILURE;
01889 
01890   if (aLineNumber >= cellMap->GetRowCount())
01891     return NS_ERROR_INVALID_ARG;
01892   
01893   *aLineFlags = 0;
01894   // not gonna touch aLineBounds right now
01895 
01896   CellData* firstCellData = cellMap->GetDataAt(aLineNumber, 0);
01897   if (!firstCellData)
01898     return NS_ERROR_FAILURE;
01899 
01900   *aFirstFrameOnLine = (nsIFrame*)firstCellData->GetCellFrame();
01901   if (!(*aFirstFrameOnLine))
01902   {
01903     while((aLineNumber > 0)&&(!(*aFirstFrameOnLine)))
01904     {
01905       aLineNumber--;
01906       firstCellData = cellMap->GetDataAt(aLineNumber, 0);
01907       *aFirstFrameOnLine = (nsIFrame*)firstCellData->GetCellFrame();
01908     }
01909   }
01910   *aNumFramesOnLine = cellMap->GetNumCellsOriginatingInRow(aLineNumber);
01911   return NS_OK;
01912 }
01913   
01914 NS_IMETHODIMP
01915 nsTableRowGroupFrame::FindLineContaining(nsIFrame* aFrame, 
01916                                          PRInt32*  aLineNumberResult)
01917 {
01918   NS_ENSURE_ARG_POINTER(aFrame);
01919   NS_ENSURE_ARG_POINTER(aLineNumberResult);
01920 
01921   // make sure it is a rowFrame in the RowGroup
01922   // - it should be, but we do not validate in every case (see bug 88849)
01923   if (aFrame->GetType() != nsLayoutAtoms::tableRowFrame) {
01924     NS_WARNING("RowGroup contains a frame that is not a row");
01925     *aLineNumberResult = 0;
01926     return NS_ERROR_FAILURE;
01927   } 
01928 
01929   nsTableRowFrame* rowFrame = (nsTableRowFrame*)aFrame;
01930   *aLineNumberResult = rowFrame->GetRowIndex();
01931 
01932   return NS_OK;
01933 }
01934 
01935 NS_IMETHODIMP
01936 nsTableRowGroupFrame::FindLineAt(nscoord  aY, 
01937                                  PRInt32* aLineNumberResult)
01938 {
01939   return NS_ERROR_NOT_IMPLEMENTED;
01940 }
01941 #ifdef IBMBIDI
01942 NS_IMETHODIMP
01943 nsTableRowGroupFrame::CheckLineOrder(PRInt32                  aLine,
01944                                      PRBool                   *aIsReordered,
01945                                      nsIFrame                 **aFirstVisual,
01946                                      nsIFrame                 **aLastVisual)
01947 {
01948   *aIsReordered = PR_FALSE;
01949   return NS_OK;
01950 }
01951 #endif // IBMBIDI
01952   
01953 NS_IMETHODIMP
01954 nsTableRowGroupFrame::FindFrameAt(PRInt32    aLineNumber, 
01955                                   nscoord    aX, 
01956                                   nsIFrame** aFrameFound,
01957                                   PRBool*    aXIsBeforeFirstFrame, 
01958                                   PRBool*    aXIsAfterLastFrame)
01959 {
01960   PRInt32 colCount = 0;
01961   CellData* cellData;
01962   nsIFrame* tempFrame = nsnull;
01963 
01964   nsTableFrame* parentFrame = nsnull;
01965   nsTableFrame::GetTableFrame(this, parentFrame);
01966   nsTableCellMap* cellMap = parentFrame->GetCellMap();
01967   if (!cellMap)
01968      return NS_ERROR_FAILURE;
01969 
01970   colCount = cellMap->GetColCount();
01971 
01972   *aXIsBeforeFirstFrame = PR_FALSE;
01973   *aXIsAfterLastFrame = PR_FALSE;
01974 
01975   PRBool gotParentRect = PR_FALSE;
01976   for (PRInt32 i = 0; i < colCount; i++)
01977   {
01978     cellData = cellMap->GetDataAt(aLineNumber, i);
01979     if (!cellData)
01980       continue; // we hit a cellmap hole
01981     if (!cellData->IsOrig())
01982       continue;
01983     tempFrame = (nsIFrame*)cellData->GetCellFrame();
01984 
01985     if (!tempFrame)
01986       continue;
01987     
01988     nsRect tempRect = tempFrame->GetRect();//offsetting x to be in row coordinates
01989     if(!gotParentRect)
01990     {//only do this once
01991       nsIFrame* tempParentFrame = tempFrame->GetParent();
01992       if(!tempParentFrame)
01993         return NS_ERROR_FAILURE;
01994 
01995       aX -= tempParentFrame->GetPosition().x;
01996       gotParentRect = PR_TRUE;
01997     }
01998 
01999     if (i==0 &&(aX <= 0))//short circuit for negative x coords
02000     {
02001       *aXIsBeforeFirstFrame = PR_TRUE;
02002       *aFrameFound = tempFrame;
02003       return NS_OK;
02004     }
02005     if (aX < tempRect.x)
02006     {
02007       return NS_ERROR_FAILURE;
02008     }
02009     if(aX < tempRect.XMost())
02010     {
02011       *aFrameFound = tempFrame;
02012       return NS_OK;
02013     }
02014   }
02015   //x coord not found in frame, return last frame
02016   *aXIsAfterLastFrame = PR_TRUE;
02017   *aFrameFound = tempFrame;
02018   if (!(*aFrameFound))
02019     return NS_ERROR_FAILURE;
02020   return NS_OK;
02021 }
02022 
02023 NS_IMETHODIMP
02024 nsTableRowGroupFrame::GetNextSiblingOnLine(nsIFrame*& aFrame, 
02025                                            PRInt32    aLineNumber)
02026 {
02027   NS_ENSURE_ARG_POINTER(aFrame);
02028 
02029   nsITableCellLayout* cellFrame;
02030   nsresult result = CallQueryInterface(aFrame, &cellFrame);
02031   if (NS_FAILED(result))
02032     return result;
02033 
02034   nsTableFrame* parentFrame = nsnull;
02035   result = nsTableFrame::GetTableFrame(this, parentFrame);
02036   nsTableCellMap* cellMap = parentFrame->GetCellMap();
02037   if (!cellMap)
02038      return NS_ERROR_FAILURE;
02039 
02040 
02041   PRInt32 colIndex;
02042   PRInt32& colIndexRef = colIndex;
02043   cellFrame->GetColIndex(colIndexRef);
02044 
02045   CellData* cellData = cellMap->GetDataAt(aLineNumber, colIndex + 1);
02046   
02047   if (!cellData)// if this isnt a valid cell, drop down and check the next line
02048   {
02049     cellData = cellMap->GetDataAt(aLineNumber + 1, 0);
02050     if (!cellData)
02051     {
02052       //*aFrame = nsnull;
02053       return NS_ERROR_FAILURE;
02054     }
02055   }
02056 
02057   aFrame = (nsIFrame*)cellData->GetCellFrame();
02058   if (!aFrame)
02059   {
02060     //PRInt32 numCellsInRow = cellMap->GetNumCellsOriginatingInRow(aLineNumber) - 1;
02061     PRInt32 tempCol = colIndex + 1;
02062     PRInt32 tempRow = aLineNumber;
02063     while ((tempCol > 0) && (!aFrame))
02064     {
02065       tempCol--;
02066       cellData = cellMap->GetDataAt(aLineNumber, tempCol);
02067       aFrame = (nsIFrame*)cellData->GetCellFrame();
02068       if (!aFrame && (tempCol==0))
02069       {
02070         while ((tempRow > 0) && (!aFrame))
02071         {
02072           tempRow--;
02073           cellData = cellMap->GetDataAt(tempRow, 0);
02074           aFrame = (nsIFrame*)cellData->GetCellFrame();
02075         }
02076       }
02077     }
02078   }
02079   return NS_OK;
02080 }
02081 
02082 //end nsLineIterator methods
02083