LCOV - code coverage report
Current view: directory - layout/tables - nsTableRowGroupFrame.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 908 0 0.0 %
Date: 2012-06-02 Functions: 66 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Mats Palmgren <matspal@gmail.com>
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      27                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : #include "nsCOMPtr.h"
      39                 : #include "nsTableRowGroupFrame.h"
      40                 : #include "nsTableRowFrame.h"
      41                 : #include "nsTableFrame.h"
      42                 : #include "nsTableCellFrame.h"
      43                 : #include "nsPresContext.h"
      44                 : #include "nsStyleContext.h"
      45                 : #include "nsStyleConsts.h"
      46                 : #include "nsIContent.h"
      47                 : #include "nsGkAtoms.h"
      48                 : #include "nsIPresShell.h"
      49                 : #include "nsCSSRendering.h"
      50                 : #include "nsHTMLParts.h"
      51                 : #include "nsCSSFrameConstructor.h"
      52                 : #include "nsDisplayList.h"
      53                 : 
      54                 : #include "nsCellMap.h"//table cell navigation
      55                 : 
      56                 : using namespace mozilla;
      57                 : 
      58               0 : nsTableRowGroupFrame::nsTableRowGroupFrame(nsStyleContext* aContext):
      59               0 :   nsContainerFrame(aContext)
      60                 : {
      61               0 :   SetRepeatable(false);
      62               0 : }
      63                 : 
      64               0 : nsTableRowGroupFrame::~nsTableRowGroupFrame()
      65                 : {
      66               0 : }
      67                 : 
      68               0 : NS_QUERYFRAME_HEAD(nsTableRowGroupFrame)
      69               0 :   NS_QUERYFRAME_ENTRY(nsTableRowGroupFrame)
      70               0 : NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
      71                 : 
      72                 : PRInt32
      73               0 : nsTableRowGroupFrame::GetRowCount()
      74                 : {
      75                 : #ifdef DEBUG
      76               0 :   for (nsFrameList::Enumerator e(mFrames); !e.AtEnd(); e.Next()) {
      77               0 :     NS_ASSERTION(e.get()->GetStyleDisplay()->mDisplay ==
      78                 :                    NS_STYLE_DISPLAY_TABLE_ROW,
      79                 :                  "Unexpected display");
      80               0 :     NS_ASSERTION(e.get()->GetType() == nsGkAtoms::tableRowFrame,
      81                 :                  "Unexpected frame type");
      82                 :   }
      83                 : #endif
      84                 :   
      85               0 :   return mFrames.GetLength();
      86                 : }
      87                 : 
      88               0 : PRInt32 nsTableRowGroupFrame::GetStartRowIndex()
      89                 : {
      90               0 :   PRInt32 result = -1;
      91               0 :   if (mFrames.NotEmpty()) {
      92               0 :     NS_ASSERTION(mFrames.FirstChild()->GetType() == nsGkAtoms::tableRowFrame,
      93                 :                  "Unexpected frame type");
      94               0 :     result = static_cast<nsTableRowFrame*>(mFrames.FirstChild())->GetRowIndex();
      95                 :   }
      96                 :   // if the row group doesn't have any children, get it the hard way
      97               0 :   if (-1 == result) {
      98               0 :     nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
      99               0 :     return tableFrame->GetStartRowIndex(this);
     100                 :   }
     101                 :       
     102               0 :   return result;
     103                 : }
     104                 : 
     105               0 : void  nsTableRowGroupFrame::AdjustRowIndices(PRInt32 aRowIndex,
     106                 :                                              PRInt32 anAdjustment)
     107                 : {
     108               0 :   nsIFrame* rowFrame = GetFirstPrincipalChild();
     109               0 :   for ( ; rowFrame; rowFrame = rowFrame->GetNextSibling()) {
     110               0 :     if (NS_STYLE_DISPLAY_TABLE_ROW==rowFrame->GetStyleDisplay()->mDisplay) {
     111               0 :       PRInt32 index = ((nsTableRowFrame*)rowFrame)->GetRowIndex();
     112               0 :       if (index >= aRowIndex)
     113               0 :         ((nsTableRowFrame *)rowFrame)->SetRowIndex(index+anAdjustment);
     114                 :     }
     115                 :   }
     116               0 : }
     117                 : nsresult
     118               0 : nsTableRowGroupFrame::InitRepeatedFrame(nsPresContext*        aPresContext,
     119                 :                                         nsTableRowGroupFrame* aHeaderFooterFrame)
     120                 : {
     121               0 :   nsTableRowFrame* copyRowFrame = GetFirstRow();
     122               0 :   nsTableRowFrame* originalRowFrame = aHeaderFooterFrame->GetFirstRow();
     123               0 :   AddStateBits(NS_REPEATED_ROW_OR_ROWGROUP);
     124               0 :   while (copyRowFrame && originalRowFrame) {
     125               0 :     copyRowFrame->AddStateBits(NS_REPEATED_ROW_OR_ROWGROUP);
     126               0 :     int rowIndex = originalRowFrame->GetRowIndex();
     127               0 :     copyRowFrame->SetRowIndex(rowIndex);
     128                 : 
     129                 :     // For each table cell frame set its column index
     130               0 :     nsTableCellFrame* originalCellFrame = originalRowFrame->GetFirstCell();
     131               0 :     nsTableCellFrame* copyCellFrame     = copyRowFrame->GetFirstCell();
     132               0 :     while (copyCellFrame && originalCellFrame) {
     133               0 :       NS_ASSERTION(originalCellFrame->GetContent() == copyCellFrame->GetContent(),
     134                 :                    "cell frames have different content");
     135                 :       PRInt32 colIndex;
     136               0 :       originalCellFrame->GetColIndex(colIndex);
     137               0 :       copyCellFrame->SetColIndex(colIndex);
     138                 :         
     139                 :       // Move to the next cell frame
     140               0 :       copyCellFrame     = copyCellFrame->GetNextCell();
     141               0 :       originalCellFrame = originalCellFrame->GetNextCell();
     142                 :     }
     143                 :     
     144                 :     // Move to the next row frame
     145               0 :     originalRowFrame = originalRowFrame->GetNextRow();
     146               0 :     copyRowFrame = copyRowFrame->GetNextRow();
     147                 :   }
     148                 : 
     149               0 :   return NS_OK;
     150                 : }
     151                 : 
     152                 : /**
     153                 :  * We need a custom display item for table row backgrounds. This is only used
     154                 :  * when the table row is the root of a stacking context (e.g., has 'opacity').
     155                 :  * Table row backgrounds can extend beyond the row frame bounds, when
     156                 :  * the row contains row-spanning cells.
     157                 :  */
     158                 : class nsDisplayTableRowGroupBackground : public nsDisplayTableItem {
     159                 : public:
     160               0 :   nsDisplayTableRowGroupBackground(nsDisplayListBuilder* aBuilder,
     161                 :                                    nsTableRowGroupFrame* aFrame) :
     162               0 :     nsDisplayTableItem(aBuilder, aFrame) {
     163               0 :     MOZ_COUNT_CTOR(nsDisplayTableRowGroupBackground);
     164               0 :   }
     165                 : #ifdef NS_BUILD_REFCNT_LOGGING
     166               0 :   virtual ~nsDisplayTableRowGroupBackground() {
     167               0 :     MOZ_COUNT_DTOR(nsDisplayTableRowGroupBackground);
     168               0 :   }
     169                 : #endif
     170                 : 
     171                 :   virtual void Paint(nsDisplayListBuilder* aBuilder,
     172                 :                      nsRenderingContext* aCtx);
     173                 : 
     174               0 :   NS_DISPLAY_DECL_NAME("TableRowGroupBackground", TYPE_TABLE_ROW_GROUP_BACKGROUND)
     175                 : };
     176                 : 
     177                 : void
     178               0 : nsDisplayTableRowGroupBackground::Paint(nsDisplayListBuilder* aBuilder,
     179                 :                                         nsRenderingContext* aCtx)
     180                 : {
     181               0 :   nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(mFrame);
     182                 :   TableBackgroundPainter painter(tableFrame,
     183                 :                                  TableBackgroundPainter::eOrigin_TableRowGroup,
     184                 :                                  mFrame->PresContext(), *aCtx,
     185               0 :                                  mVisibleRect, ToReferenceFrame(),
     186               0 :                                  aBuilder->GetBackgroundPaintFlags());
     187               0 :   painter.PaintRowGroup(static_cast<nsTableRowGroupFrame*>(mFrame));
     188               0 : }
     189                 : 
     190                 : // Handle the child-traversal part of DisplayGenericTablePart
     191                 : static nsresult
     192               0 : DisplayRows(nsDisplayListBuilder* aBuilder, nsFrame* aFrame,
     193                 :             const nsRect& aDirtyRect, const nsDisplayListSet& aLists)
     194                 : {
     195                 :   nscoord overflowAbove;
     196               0 :   nsTableRowGroupFrame* f = static_cast<nsTableRowGroupFrame*>(aFrame);
     197                 :   // Don't try to use the row cursor if we have to descend into placeholders;
     198                 :   // we might have rows containing placeholders, where the row's overflow
     199                 :   // area doesn't intersect the dirty rect but we need to descend into the row
     200                 :   // to see out of flows.
     201                 :   // Note that we really want to check ShouldDescendIntoFrame for all
     202                 :   // the rows in |f|, but that's exactly what we're trying to avoid, so we
     203                 :   // approximate it by checking it for |f|: if it's true for any row
     204                 :   // in |f| then it's true for |f| itself.
     205               0 :   nsIFrame* kid = aBuilder->ShouldDescendIntoFrame(f) ?
     206               0 :     nsnull : f->GetFirstRowContaining(aDirtyRect.y, &overflowAbove);
     207                 :   
     208               0 :   if (kid) {
     209                 :     // have a cursor, use it
     210               0 :     while (kid) {
     211               0 :       if (kid->GetRect().y - overflowAbove >= aDirtyRect.YMost())
     212               0 :         break;
     213               0 :       nsresult rv = f->BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
     214               0 :       NS_ENSURE_SUCCESS(rv, rv);
     215               0 :       kid = kid->GetNextSibling();
     216                 :     }
     217               0 :     return NS_OK;
     218                 :   }
     219                 :   
     220                 :   // No cursor. Traverse children the hard way and build a cursor while we're at it
     221               0 :   nsTableRowGroupFrame::FrameCursorData* cursor = f->SetupRowCursor();
     222               0 :   kid = f->GetFirstPrincipalChild();
     223               0 :   while (kid) {
     224               0 :     nsresult rv = f->BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
     225               0 :     if (NS_FAILED(rv)) {
     226               0 :       f->ClearRowCursor();
     227               0 :       return rv;
     228                 :     }
     229                 :     
     230               0 :     if (cursor) {
     231               0 :       if (!cursor->AppendFrame(kid)) {
     232               0 :         f->ClearRowCursor();
     233               0 :         return NS_ERROR_OUT_OF_MEMORY;
     234                 :       }
     235                 :     }
     236                 :   
     237               0 :     kid = kid->GetNextSibling();
     238                 :   }
     239               0 :   if (cursor) {
     240               0 :     cursor->FinishBuildingCursor();
     241                 :   }
     242                 : 
     243               0 :   return NS_OK;
     244                 : }
     245                 : 
     246                 : NS_IMETHODIMP
     247               0 : nsTableRowGroupFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
     248                 :                                        const nsRect&           aDirtyRect,
     249                 :                                        const nsDisplayListSet& aLists)
     250                 : {
     251               0 :   nsDisplayTableItem* item = nsnull;
     252               0 :   if (IsVisibleInSelection(aBuilder)) {
     253               0 :     bool isRoot = aBuilder->IsAtRootOfPseudoStackingContext();
     254               0 :     if (isRoot) {
     255                 :       // This background is created regardless of whether this frame is
     256                 :       // visible or not. Visibility decisions are delegated to the
     257                 :       // table background painter.
     258               0 :       item = new (aBuilder) nsDisplayTableRowGroupBackground(aBuilder, this);
     259               0 :       nsresult rv = aLists.BorderBackground()->AppendNewToTop(item);
     260               0 :       NS_ENSURE_SUCCESS(rv, rv);
     261                 :     }
     262                 :   }  
     263                 :   return nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect,
     264               0 :                                                aLists, item, DisplayRows);
     265                 : }
     266                 : 
     267                 : PRIntn
     268               0 : nsTableRowGroupFrame::GetSkipSides() const
     269                 : {
     270               0 :   PRIntn skip = 0;
     271               0 :   if (nsnull != GetPrevInFlow()) {
     272               0 :     skip |= 1 << NS_SIDE_TOP;
     273                 :   }
     274               0 :   if (nsnull != GetNextInFlow()) {
     275               0 :     skip |= 1 << NS_SIDE_BOTTOM;
     276                 :   }
     277               0 :   return skip;
     278                 : }
     279                 : 
     280                 : // Position and size aKidFrame and update our reflow state. The origin of
     281                 : // aKidRect is relative to the upper-left origin of our frame
     282                 : void 
     283               0 : nsTableRowGroupFrame::PlaceChild(nsPresContext*         aPresContext,
     284                 :                                  nsRowGroupReflowState& aReflowState,
     285                 :                                  nsIFrame*              aKidFrame,
     286                 :                                  nsHTMLReflowMetrics&   aDesiredSize,
     287                 :                                  const nsRect&          aOriginalKidRect,
     288                 :                                  const nsRect&          aOriginalKidVisualOverflow)
     289                 : {
     290                 :   bool isFirstReflow =
     291               0 :     (aKidFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
     292                 : 
     293                 :   // Place and size the child
     294                 :   FinishReflowChild(aKidFrame, aPresContext, nsnull, aDesiredSize, 0,
     295               0 :                     aReflowState.y, 0);
     296                 : 
     297                 :   nsTableFrame::InvalidateFrame(aKidFrame, aOriginalKidRect,
     298               0 :                                 aOriginalKidVisualOverflow, isFirstReflow);
     299                 : 
     300                 :   // Adjust the running y-offset
     301               0 :   aReflowState.y += aDesiredSize.height;
     302                 : 
     303                 :   // If our height is constrained then update the available height
     304               0 :   if (NS_UNCONSTRAINEDSIZE != aReflowState.availSize.height) {
     305               0 :     aReflowState.availSize.height -= aDesiredSize.height;
     306                 :   }
     307               0 : }
     308                 : 
     309                 : void
     310               0 : nsTableRowGroupFrame::InitChildReflowState(nsPresContext&     aPresContext, 
     311                 :                                            bool               aBorderCollapse,
     312                 :                                            nsHTMLReflowState& aReflowState)                                    
     313                 : {
     314               0 :   nsMargin collapseBorder;
     315               0 :   nsMargin padding(0,0,0,0);
     316               0 :   nsMargin* pCollapseBorder = nsnull;
     317               0 :   if (aBorderCollapse) {
     318               0 :     nsTableRowFrame *rowFrame = do_QueryFrame(aReflowState.frame);
     319               0 :     if (rowFrame) {
     320               0 :       pCollapseBorder = rowFrame->GetBCBorderWidth(collapseBorder);
     321                 :     }
     322                 :   }
     323               0 :   aReflowState.Init(&aPresContext, -1, -1, pCollapseBorder, &padding);
     324               0 : }
     325                 : 
     326                 : static void
     327               0 : CacheRowHeightsForPrinting(nsPresContext*   aPresContext,
     328                 :                            nsTableRowFrame* aFirstRow)
     329                 : {
     330               0 :   for (nsTableRowFrame* row = aFirstRow; row; row = row->GetNextRow()) {
     331               0 :     if (!row->GetPrevInFlow()) {
     332               0 :       row->SetHasUnpaginatedHeight(true);
     333               0 :       row->SetUnpaginatedHeight(aPresContext, row->GetSize().height);
     334                 :     }
     335                 :   }
     336               0 : }
     337                 : 
     338                 : nsresult
     339               0 : nsTableRowGroupFrame::ReflowChildren(nsPresContext*         aPresContext,
     340                 :                                      nsHTMLReflowMetrics&   aDesiredSize,
     341                 :                                      nsRowGroupReflowState& aReflowState,
     342                 :                                      nsReflowStatus&        aStatus,
     343                 :                                      bool*                aPageBreakBeforeEnd)
     344                 : {
     345               0 :   if (aPageBreakBeforeEnd) 
     346               0 :     *aPageBreakBeforeEnd = false;
     347                 : 
     348               0 :   nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
     349               0 :   nsresult rv = NS_OK;
     350               0 :   const bool borderCollapse = tableFrame->IsBorderCollapse();
     351               0 :   nscoord cellSpacingY = tableFrame->GetCellSpacingY();
     352                 : 
     353                 :   // XXXldb Should we really be checking this rather than available height?
     354                 :   // (Think about multi-column layout!)
     355               0 :   bool isPaginated = aPresContext->IsPaginated() && 
     356               0 :                        NS_UNCONSTRAINEDSIZE != aReflowState.availSize.height;
     357                 : 
     358               0 :   bool haveRow = false;
     359               0 :   bool reflowAllKids = aReflowState.reflowState.ShouldReflowAllKids() ||
     360               0 :                          tableFrame->IsGeometryDirty();
     361               0 :   bool needToCalcRowHeights = reflowAllKids;
     362                 : 
     363               0 :   nsIFrame *prevKidFrame = nsnull;
     364               0 :   for (nsIFrame* kidFrame = mFrames.FirstChild(); kidFrame;
     365                 :        prevKidFrame = kidFrame, kidFrame = kidFrame->GetNextSibling()) {
     366               0 :     nsTableRowFrame *rowFrame = do_QueryFrame(kidFrame);
     367               0 :     if (!rowFrame) {
     368                 :       // XXXldb nsCSSFrameConstructor needs to enforce this!
     369               0 :       NS_NOTREACHED("yikes, a non-row child");
     370               0 :       continue;
     371                 :     }
     372                 : 
     373               0 :     haveRow = true;
     374                 : 
     375                 :     // Reflow the row frame
     376               0 :     if (reflowAllKids ||
     377               0 :         NS_SUBTREE_DIRTY(kidFrame) ||
     378                 :         (aReflowState.reflowState.mFlags.mSpecialHeightReflow &&
     379               0 :          (isPaginated || (kidFrame->GetStateBits() &
     380                 :                           NS_FRAME_CONTAINS_RELATIVE_HEIGHT)))) {
     381               0 :       nsRect oldKidRect = kidFrame->GetRect();
     382               0 :       nsRect oldKidVisualOverflow = kidFrame->GetVisualOverflowRect();
     383                 : 
     384                 :       // XXXldb We used to only pass aDesiredSize.mFlags through for the
     385                 :       // incremental reflow codepath.
     386               0 :       nsHTMLReflowMetrics desiredSize(aDesiredSize.mFlags);
     387               0 :       desiredSize.width = desiredSize.height = 0;
     388                 :   
     389                 :       // Reflow the child into the available space, giving it as much height as
     390                 :       // it wants. We'll deal with splitting later after we've computed the row
     391                 :       // heights, taking into account cells with row spans...
     392               0 :       nsSize kidAvailSize(aReflowState.availSize.width, NS_UNCONSTRAINEDSIZE);
     393                 :       nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState,
     394                 :                                        kidFrame, kidAvailSize,
     395               0 :                                        -1, -1, false);
     396               0 :       InitChildReflowState(*aPresContext, borderCollapse, kidReflowState);
     397                 : 
     398                 :       // This can indicate that columns were resized.
     399               0 :       if (aReflowState.reflowState.mFlags.mHResize)
     400               0 :         kidReflowState.mFlags.mHResize = true;
     401                 :      
     402               0 :       NS_ASSERTION(kidFrame == mFrames.FirstChild() || prevKidFrame, 
     403                 :                    "If we're not on the first frame, we should have a "
     404                 :                    "previous sibling...");
     405                 :       // If prev row has nonzero YMost, then we can't be at the top of the page
     406               0 :       if (prevKidFrame && prevKidFrame->GetRect().YMost() > 0) {
     407               0 :         kidReflowState.mFlags.mIsTopOfPage = false;
     408                 :       }
     409                 : 
     410                 :       rv = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState,
     411                 :                        0, aReflowState.y, NS_FRAME_INVALIDATE_ON_MOVE,
     412               0 :                        aStatus);
     413                 : 
     414                 :       // Place the child
     415                 :       PlaceChild(aPresContext, aReflowState, kidFrame, desiredSize,
     416               0 :                  oldKidRect, oldKidVisualOverflow);
     417               0 :       aReflowState.y += cellSpacingY;
     418                 : 
     419               0 :       if (!reflowAllKids) {
     420               0 :         if (IsSimpleRowFrame(aReflowState.tableFrame, kidFrame)) {
     421                 :           // Inform the row of its new height.
     422               0 :           rowFrame->DidResize();
     423                 :           // the overflow area may have changed inflate the overflow area
     424               0 :           const nsStylePosition *stylePos = GetStylePosition();
     425               0 :           nsStyleUnit unit = stylePos->mHeight.GetUnit();
     426               0 :           if (aReflowState.tableFrame->IsAutoHeight() &&
     427                 :               unit != eStyleUnit_Coord) {
     428                 :             // Because other cells in the row may need to be aligned
     429                 :             // differently, repaint the entire row
     430                 :             nsRect kidRect(0, aReflowState.y,
     431               0 :                            desiredSize.width, desiredSize.height);
     432               0 :             Invalidate(kidRect);
     433                 :             
     434                 :             // Invalidate the area we're offseting. Note that we only
     435                 :             // repaint within our existing frame bounds.
     436               0 :             if (kidRect.YMost() < mRect.height) {
     437                 :               nsRect  dirtyRect(0, kidRect.YMost(),
     438               0 :                                 mRect.width, mRect.height - kidRect.YMost());
     439               0 :               Invalidate(dirtyRect);
     440                 :             }
     441                 :           }
     442               0 :           else if (oldKidRect.height != desiredSize.height)
     443               0 :             needToCalcRowHeights = true;
     444                 :         } else {
     445               0 :           needToCalcRowHeights = true;
     446                 :         }
     447                 :       }
     448                 : 
     449               0 :       if (isPaginated && aPageBreakBeforeEnd && !*aPageBreakBeforeEnd) {
     450               0 :         nsTableRowFrame* nextRow = rowFrame->GetNextRow();
     451               0 :         if (nextRow) {
     452               0 :           *aPageBreakBeforeEnd = nsTableFrame::PageBreakAfter(kidFrame, nextRow);
     453                 :         }
     454                 :       }
     455                 :     } else {
     456               0 :       SlideChild(aReflowState, kidFrame);
     457                 : 
     458                 :       // Adjust the running y-offset so we know where the next row should be placed
     459               0 :       nscoord height = kidFrame->GetSize().height + cellSpacingY;
     460               0 :       aReflowState.y += height;
     461                 : 
     462               0 :       if (NS_UNCONSTRAINEDSIZE != aReflowState.availSize.height) {
     463               0 :         aReflowState.availSize.height -= height;
     464                 :       }
     465                 :     }
     466               0 :     ConsiderChildOverflow(aDesiredSize.mOverflowAreas, kidFrame);
     467                 :   }
     468                 : 
     469               0 :   if (haveRow)
     470               0 :     aReflowState.y -= cellSpacingY;
     471                 : 
     472                 :   // Return our desired rect
     473               0 :   aDesiredSize.width = aReflowState.reflowState.availableWidth;
     474               0 :   aDesiredSize.height = aReflowState.y;
     475                 : 
     476               0 :   if (aReflowState.reflowState.mFlags.mSpecialHeightReflow) {
     477               0 :     DidResizeRows(aDesiredSize);
     478               0 :     if (isPaginated) {
     479               0 :       CacheRowHeightsForPrinting(aPresContext, GetFirstRow());
     480                 :     }
     481                 :   }
     482               0 :   else if (needToCalcRowHeights) {
     483               0 :     CalculateRowHeights(aPresContext, aDesiredSize, aReflowState.reflowState);
     484               0 :     if (!reflowAllKids) {
     485                 :       // Because we don't know what changed repaint everything.
     486                 :       // XXX We should change CalculateRowHeights() to return the bounding
     487                 :       // rect of what changed. Or whether anything moved or changed size...
     488               0 :       nsRect  dirtyRect(0, 0, mRect.width, mRect.height);
     489               0 :       Invalidate(dirtyRect);
     490                 :     }
     491                 :   }
     492                 : 
     493               0 :   return rv;
     494                 : }
     495                 : 
     496                 : nsTableRowFrame*  
     497               0 : nsTableRowGroupFrame::GetFirstRow() 
     498                 : {
     499               0 :   for (nsIFrame* childFrame = mFrames.FirstChild(); childFrame;
     500                 :        childFrame = childFrame->GetNextSibling()) {
     501               0 :     nsTableRowFrame *rowFrame = do_QueryFrame(childFrame);
     502               0 :     if (rowFrame) {
     503               0 :       return rowFrame;
     504                 :     }
     505                 :   }
     506               0 :   return nsnull;
     507                 : }
     508                 : 
     509                 : 
     510               0 : struct RowInfo {
     511               0 :   RowInfo() { height = pctHeight = hasStyleHeight = hasPctHeight = isSpecial = 0; }
     512                 :   unsigned height;       // content height or fixed height, excluding pct height
     513                 :   unsigned pctHeight:29; // pct height
     514                 :   unsigned hasStyleHeight:1; 
     515                 :   unsigned hasPctHeight:1; 
     516                 :   unsigned isSpecial:1; // there is no cell originating in the row with rowspan=1 and there are at
     517                 :                         // least 2 cells spanning the row and there is no style height on the row
     518                 : };
     519                 : 
     520                 : static void
     521               0 : UpdateHeights(RowInfo& aRowInfo,
     522                 :               nscoord  aAdditionalHeight,
     523                 :               nscoord& aTotal,
     524                 :               nscoord& aUnconstrainedTotal)
     525                 : {
     526               0 :   aRowInfo.height += aAdditionalHeight;
     527               0 :   aTotal          += aAdditionalHeight;
     528               0 :   if (!aRowInfo.hasStyleHeight) {
     529               0 :     aUnconstrainedTotal += aAdditionalHeight;
     530                 :   }
     531               0 : }
     532                 : 
     533                 : void 
     534               0 : nsTableRowGroupFrame::DidResizeRows(nsHTMLReflowMetrics& aDesiredSize)
     535                 : {
     536                 :   // update the cells spanning rows with their new heights
     537                 :   // this is the place where all of the cells in the row get set to the height of the row
     538                 :   // Reset the overflow area
     539               0 :   aDesiredSize.mOverflowAreas.Clear();
     540               0 :   for (nsTableRowFrame* rowFrame = GetFirstRow();
     541                 :        rowFrame; rowFrame = rowFrame->GetNextRow()) {
     542               0 :     rowFrame->DidResize();
     543               0 :     ConsiderChildOverflow(aDesiredSize.mOverflowAreas, rowFrame);
     544                 :   }
     545               0 : }
     546                 : 
     547                 : // This calculates the height of all the rows and takes into account 
     548                 : // style height on the row group, style heights on rows and cells, style heights on rowspans. 
     549                 : // Actual row heights will be adjusted later if the table has a style height.
     550                 : // Even if rows don't change height, this method must be called to set the heights of each
     551                 : // cell in the row to the height of its row.
     552                 : void 
     553               0 : nsTableRowGroupFrame::CalculateRowHeights(nsPresContext*           aPresContext, 
     554                 :                                           nsHTMLReflowMetrics&     aDesiredSize,
     555                 :                                           const nsHTMLReflowState& aReflowState)
     556                 : {
     557               0 :   nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
     558               0 :   const bool isPaginated = aPresContext->IsPaginated();
     559                 : 
     560                 :   // all table cells have the same top and bottom margins, namely cellSpacingY
     561               0 :   nscoord cellSpacingY = tableFrame->GetCellSpacingY();
     562                 : 
     563               0 :   PRInt32 numEffCols = tableFrame->GetEffectiveColCount();
     564                 : 
     565               0 :   PRInt32 startRowIndex = GetStartRowIndex();
     566                 :   // find the row corresponding to the row index we just found
     567               0 :   nsTableRowFrame* startRowFrame = GetFirstRow();
     568                 : 
     569               0 :   if (!startRowFrame) return;
     570                 : 
     571                 :   // the current row group height is the y origin of the 1st row we are about to calculated a height for
     572               0 :   nscoord startRowGroupHeight = startRowFrame->GetPosition().y;
     573                 : 
     574               0 :   PRInt32 numRows = GetRowCount() - (startRowFrame->GetRowIndex() - GetStartRowIndex());
     575                 :   // collect the current height of each row.  nscoord* rowHeights = nsnull;
     576               0 :   if (numRows <= 0)
     577               0 :     return;
     578                 : 
     579               0 :   nsTArray<RowInfo> rowInfo;
     580               0 :   if (!rowInfo.AppendElements(numRows)) {
     581                 :     return;
     582                 :   }
     583                 : 
     584               0 :   bool    hasRowSpanningCell = false;
     585               0 :   nscoord heightOfRows = 0;
     586               0 :   nscoord heightOfUnStyledRows = 0;
     587                 :   // Get the height of each row without considering rowspans. This will be the max of 
     588                 :   // the largest desired height of each cell, the largest style height of each cell, 
     589                 :   // the style height of the row.
     590               0 :   nscoord pctHeightBasis = GetHeightBasis(aReflowState);
     591                 :   PRInt32 rowIndex; // the index in rowInfo, not among the rows in the row group
     592                 :   nsTableRowFrame* rowFrame;
     593               0 :   for (rowFrame = startRowFrame, rowIndex = 0; rowFrame; rowFrame = rowFrame->GetNextRow(), rowIndex++) {
     594               0 :     nscoord nonPctHeight = rowFrame->GetContentHeight();
     595               0 :     if (isPaginated) {
     596               0 :       nonPctHeight = NS_MAX(nonPctHeight, rowFrame->GetSize().height);
     597                 :     }
     598               0 :     if (!rowFrame->GetPrevInFlow()) {
     599               0 :       if (rowFrame->HasPctHeight()) {
     600               0 :         rowInfo[rowIndex].hasPctHeight = true;
     601               0 :         rowInfo[rowIndex].pctHeight = rowFrame->GetHeight(pctHeightBasis);
     602                 :       }
     603               0 :       rowInfo[rowIndex].hasStyleHeight = rowFrame->HasStyleHeight();
     604               0 :       nonPctHeight = NS_MAX(nonPctHeight, rowFrame->GetFixedHeight());
     605                 :     }
     606               0 :     UpdateHeights(rowInfo[rowIndex], nonPctHeight, heightOfRows, heightOfUnStyledRows);
     607                 : 
     608               0 :     if (!rowInfo[rowIndex].hasStyleHeight) {
     609               0 :       if (isPaginated || tableFrame->HasMoreThanOneCell(rowIndex + startRowIndex)) {
     610               0 :         rowInfo[rowIndex].isSpecial = true;
     611                 :         // iteratate the row's cell frames to see if any do not have rowspan > 1
     612               0 :         nsTableCellFrame* cellFrame = rowFrame->GetFirstCell();
     613               0 :         while (cellFrame) {
     614               0 :           PRInt32 rowSpan = tableFrame->GetEffectiveRowSpan(rowIndex + startRowIndex, *cellFrame);
     615               0 :           if (1 == rowSpan) { 
     616               0 :             rowInfo[rowIndex].isSpecial = false;
     617               0 :             break;
     618                 :           }
     619               0 :           cellFrame = cellFrame->GetNextCell(); 
     620                 :         }
     621                 :       }
     622                 :     }
     623                 :     // See if a cell spans into the row. If so we'll have to do the next step
     624               0 :     if (!hasRowSpanningCell) {
     625               0 :       if (tableFrame->RowIsSpannedInto(rowIndex + startRowIndex, numEffCols)) {
     626               0 :         hasRowSpanningCell = true;
     627                 :       }
     628                 :     }
     629                 :   }
     630                 : 
     631               0 :   if (hasRowSpanningCell) {
     632                 :     // Get the height of cells with rowspans and allocate any extra space to the rows they span 
     633                 :     // iteratate the child frames and process the row frames among them
     634               0 :     for (rowFrame = startRowFrame, rowIndex = 0; rowFrame; rowFrame = rowFrame->GetNextRow(), rowIndex++) {
     635                 :       // See if the row has an originating cell with rowspan > 1. We cannot determine this for a row in a 
     636                 :       // continued row group by calling RowHasSpanningCells, because the row's fif may not have any originating
     637                 :       // cells yet the row may have a continued cell which originates in it.
     638               0 :       if (GetPrevInFlow() || tableFrame->RowHasSpanningCells(startRowIndex + rowIndex, numEffCols)) {
     639               0 :         nsTableCellFrame* cellFrame = rowFrame->GetFirstCell();
     640                 :         // iteratate the row's cell frames 
     641               0 :         while (cellFrame) {
     642               0 :           PRInt32 rowSpan = tableFrame->GetEffectiveRowSpan(rowIndex + startRowIndex, *cellFrame);
     643               0 :           if ((rowIndex + rowSpan) > numRows) {
     644                 :             // there might be rows pushed already to the nextInFlow
     645               0 :             rowSpan = numRows - rowIndex;
     646                 :           }
     647               0 :           if (rowSpan > 1) { // a cell with rowspan > 1, determine the height of the rows it spans
     648               0 :             nscoord heightOfRowsSpanned = 0;
     649               0 :             nscoord heightOfUnStyledRowsSpanned = 0;
     650               0 :             nscoord numSpecialRowsSpanned = 0; 
     651               0 :             nscoord cellSpacingTotal = 0;
     652                 :             PRInt32 spanX;
     653               0 :             for (spanX = 0; spanX < rowSpan; spanX++) {
     654               0 :               heightOfRowsSpanned += rowInfo[rowIndex + spanX].height;
     655               0 :               if (!rowInfo[rowIndex + spanX].hasStyleHeight) {
     656               0 :                 heightOfUnStyledRowsSpanned += rowInfo[rowIndex + spanX].height;
     657                 :               }
     658               0 :               if (0 != spanX) {
     659               0 :                 cellSpacingTotal += cellSpacingY;
     660                 :               }
     661               0 :               if (rowInfo[rowIndex + spanX].isSpecial) {
     662               0 :                 numSpecialRowsSpanned++;
     663                 :               }
     664                 :             } 
     665               0 :             nscoord heightOfAreaSpanned = heightOfRowsSpanned + cellSpacingTotal;
     666                 :             // get the height of the cell 
     667               0 :             nsSize cellFrameSize = cellFrame->GetSize();
     668               0 :             nsSize cellDesSize = cellFrame->GetDesiredSize();
     669               0 :             rowFrame->CalculateCellActualHeight(cellFrame, cellDesSize.height);
     670               0 :             cellFrameSize.height = cellDesSize.height;
     671               0 :             if (cellFrame->HasVerticalAlignBaseline()) {
     672                 :               // to ensure that a spanning cell with a long descender doesn't
     673                 :               // collide with the next row, we need to take into account the shift
     674                 :               // that will be done to align the cell on the baseline of the row.
     675               0 :               cellFrameSize.height += rowFrame->GetMaxCellAscent() -
     676               0 :                                       cellFrame->GetCellBaseline();
     677                 :             }
     678                 :   
     679               0 :             if (heightOfAreaSpanned < cellFrameSize.height) {
     680                 :               // the cell's height is larger than the available space of the rows it
     681                 :               // spans so distribute the excess height to the rows affected
     682               0 :               nscoord extra     = cellFrameSize.height - heightOfAreaSpanned;
     683               0 :               nscoord extraUsed = 0;
     684               0 :               if (0 == numSpecialRowsSpanned) {
     685                 :                 //NS_ASSERTION(heightOfRowsSpanned > 0, "invalid row span situation");
     686               0 :                 bool haveUnStyledRowsSpanned = (heightOfUnStyledRowsSpanned > 0);
     687                 :                 nscoord divisor = (haveUnStyledRowsSpanned) 
     688               0 :                                   ? heightOfUnStyledRowsSpanned : heightOfRowsSpanned;
     689               0 :                 if (divisor > 0) {
     690               0 :                   for (spanX = rowSpan - 1; spanX >= 0; spanX--) {
     691               0 :                     if (!haveUnStyledRowsSpanned || !rowInfo[rowIndex + spanX].hasStyleHeight) {
     692                 :                       // The amount of additional space each row gets is proportional to its height
     693               0 :                       float percent = ((float)rowInfo[rowIndex + spanX].height) / ((float)divisor);
     694                 :                     
     695                 :                       // give rows their percentage, except for the first row which gets the remainder
     696                 :                       nscoord extraForRow = (0 == spanX) ? extra - extraUsed  
     697               0 :                                                          : NSToCoordRound(((float)(extra)) * percent);
     698               0 :                       extraForRow = NS_MIN(extraForRow, extra - extraUsed);
     699                 :                       // update the row height
     700               0 :                       UpdateHeights(rowInfo[rowIndex + spanX], extraForRow, heightOfRows, heightOfUnStyledRows);
     701               0 :                       extraUsed += extraForRow;
     702               0 :                       if (extraUsed >= extra) {
     703               0 :                         NS_ASSERTION((extraUsed == extra), "invalid row height calculation");
     704               0 :                         break;
     705                 :                       }
     706                 :                     }
     707                 :                   }
     708                 :                 }
     709                 :                 else {
     710                 :                   // put everything in the last row
     711               0 :                   UpdateHeights(rowInfo[rowIndex + rowSpan - 1], extra, heightOfRows, heightOfUnStyledRows);
     712                 :                 }
     713                 :               }
     714                 :               else {
     715                 :                 // give the extra to the special rows
     716               0 :                 nscoord numSpecialRowsAllocated = 0;
     717               0 :                 for (spanX = rowSpan - 1; spanX >= 0; spanX--) {
     718               0 :                   if (rowInfo[rowIndex + spanX].isSpecial) {
     719                 :                     // The amount of additional space each degenerate row gets is proportional to the number of them
     720               0 :                     float percent = 1.0f / ((float)numSpecialRowsSpanned);
     721                 :                     
     722                 :                     // give rows their percentage, except for the first row which gets the remainder
     723                 :                     nscoord extraForRow = (numSpecialRowsSpanned - 1 == numSpecialRowsAllocated) 
     724                 :                                           ? extra - extraUsed  
     725               0 :                                           : NSToCoordRound(((float)(extra)) * percent);
     726               0 :                     extraForRow = NS_MIN(extraForRow, extra - extraUsed);
     727                 :                     // update the row height
     728               0 :                     UpdateHeights(rowInfo[rowIndex + spanX], extraForRow, heightOfRows, heightOfUnStyledRows);
     729               0 :                     extraUsed += extraForRow;
     730               0 :                     if (extraUsed >= extra) {
     731               0 :                       NS_ASSERTION((extraUsed == extra), "invalid row height calculation");
     732               0 :                       break;
     733                 :                     }
     734                 :                   }
     735                 :                 }
     736                 :               }
     737                 :             } 
     738                 :           } // if (rowSpan > 1)
     739               0 :           cellFrame = cellFrame->GetNextCell(); 
     740                 :         } // while (cellFrame)
     741                 :       } // if (tableFrame->RowHasSpanningCells(startRowIndex + rowIndex) {
     742                 :     } // while (rowFrame)
     743                 :   }
     744                 : 
     745                 :   // pct height rows have already got their content heights. Give them their pct heights up to pctHeightBasis
     746               0 :   nscoord extra = pctHeightBasis - heightOfRows;
     747               0 :   for (rowFrame = startRowFrame, rowIndex = 0; rowFrame && (extra > 0); rowFrame = rowFrame->GetNextRow(), rowIndex++) {
     748               0 :     RowInfo& rInfo = rowInfo[rowIndex];
     749               0 :     if (rInfo.hasPctHeight) {
     750                 :       nscoord rowExtra = (rInfo.pctHeight > rInfo.height)  
     751               0 :                          ? rInfo.pctHeight - rInfo.height: 0;
     752               0 :       rowExtra = NS_MIN(rowExtra, extra);
     753               0 :       UpdateHeights(rInfo, rowExtra, heightOfRows, heightOfUnStyledRows);
     754               0 :       extra -= rowExtra;
     755                 :     }
     756                 :   }
     757                 : 
     758               0 :   bool styleHeightAllocation = false;
     759               0 :   nscoord rowGroupHeight = startRowGroupHeight + heightOfRows + ((numRows - 1) * cellSpacingY);
     760                 :   // if we have a style height, allocate the extra height to unconstrained rows
     761               0 :   if ((aReflowState.ComputedHeight() > rowGroupHeight) && 
     762               0 :       (NS_UNCONSTRAINEDSIZE != aReflowState.ComputedHeight())) {
     763               0 :     nscoord extraComputedHeight = aReflowState.ComputedHeight() - rowGroupHeight;
     764               0 :     nscoord extraUsed = 0;
     765               0 :     bool haveUnStyledRows = (heightOfUnStyledRows > 0);
     766                 :     nscoord divisor = (haveUnStyledRows) 
     767               0 :                       ? heightOfUnStyledRows : heightOfRows;
     768               0 :     if (divisor > 0) {
     769               0 :       styleHeightAllocation = true;
     770               0 :       for (rowIndex = 0; rowIndex < numRows; rowIndex++) {
     771               0 :         if (!haveUnStyledRows || !rowInfo[rowIndex].hasStyleHeight) {
     772                 :           // The amount of additional space each row gets is based on the
     773                 :           // percentage of space it occupies
     774               0 :           float percent = ((float)rowInfo[rowIndex].height) / ((float)divisor);
     775                 :           // give rows their percentage, except for the last row which gets the remainder
     776                 :           nscoord extraForRow = (numRows - 1 == rowIndex) 
     777                 :                                 ? extraComputedHeight - extraUsed  
     778               0 :                                 : NSToCoordRound(((float)extraComputedHeight) * percent);
     779               0 :           extraForRow = NS_MIN(extraForRow, extraComputedHeight - extraUsed);
     780                 :           // update the row height
     781               0 :           UpdateHeights(rowInfo[rowIndex], extraForRow, heightOfRows, heightOfUnStyledRows);
     782               0 :           extraUsed += extraForRow;
     783               0 :           if (extraUsed >= extraComputedHeight) {
     784               0 :             NS_ASSERTION((extraUsed == extraComputedHeight), "invalid row height calculation");
     785               0 :             break;
     786                 :           }
     787                 :         }
     788                 :       }
     789                 :     }
     790               0 :     rowGroupHeight = aReflowState.ComputedHeight();
     791                 :   }
     792                 : 
     793               0 :   nscoord yOrigin = startRowGroupHeight;
     794                 :   // update the rows with their (potentially) new heights
     795               0 :   for (rowFrame = startRowFrame, rowIndex = 0; rowFrame; rowFrame = rowFrame->GetNextRow(), rowIndex++) {
     796               0 :     nsRect rowBounds = rowFrame->GetRect();
     797               0 :     nsRect rowVisualOverflow = rowFrame->GetVisualOverflowRect();
     798                 : 
     799               0 :     bool movedFrame = (rowBounds.y != yOrigin);  
     800               0 :     nscoord rowHeight = (rowInfo[rowIndex].height > 0) ? rowInfo[rowIndex].height : 0;
     801                 :     
     802               0 :     if (movedFrame || (rowHeight != rowBounds.height)) {
     803                 :       // Resize/move the row to its final size and position
     804               0 :       if (movedFrame) {
     805               0 :         rowFrame->InvalidateFrameSubtree();
     806                 :       }
     807                 :       
     808                 :       rowFrame->SetRect(nsRect(rowBounds.x, yOrigin, rowBounds.width,
     809               0 :                                rowHeight));
     810                 : 
     811                 :       nsTableFrame::InvalidateFrame(rowFrame, rowBounds, rowVisualOverflow,
     812               0 :                                     false);
     813                 :     }
     814               0 :     if (movedFrame) {
     815               0 :       nsTableFrame::RePositionViews(rowFrame);
     816                 :       // XXXbz we don't need to update our overflow area?
     817                 :     }
     818               0 :     yOrigin += rowHeight + cellSpacingY;
     819                 :   }
     820                 : 
     821               0 :   if (isPaginated && styleHeightAllocation) {
     822                 :     // since the row group has a style height, cache the row heights, so next in flows can honor them 
     823               0 :     CacheRowHeightsForPrinting(aPresContext, GetFirstRow());
     824                 :   }
     825                 : 
     826               0 :   DidResizeRows(aDesiredSize);
     827                 : 
     828               0 :   aDesiredSize.height = rowGroupHeight; // Adjust our desired size
     829                 : }
     830                 : 
     831                 : nscoord
     832               0 : nsTableRowGroupFrame::CollapseRowGroupIfNecessary(nscoord aYTotalOffset,
     833                 :                                                   nscoord aWidth)
     834                 : {
     835               0 :   nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
     836               0 :   const nsStyleVisibility* groupVis = GetStyleVisibility();
     837               0 :   bool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE == groupVis->mVisible);
     838               0 :   if (collapseGroup) {
     839               0 :     tableFrame->SetNeedToCollapse(true);
     840                 :   }
     841                 : 
     842               0 :   nsOverflowAreas overflow;
     843                 : 
     844               0 :   nsTableRowFrame* rowFrame= GetFirstRow();
     845               0 :   bool didCollapse = false;
     846               0 :   nscoord yGroupOffset = 0;
     847               0 :   while (rowFrame) {
     848                 :     yGroupOffset += rowFrame->CollapseRowIfNecessary(yGroupOffset,
     849                 :                                                      aWidth, collapseGroup,
     850               0 :                                                      didCollapse);
     851               0 :     ConsiderChildOverflow(overflow, rowFrame);
     852               0 :     rowFrame = rowFrame->GetNextRow();
     853                 :   }
     854                 : 
     855               0 :   nsRect groupRect = GetRect();
     856               0 :   nsRect oldGroupRect = groupRect;
     857               0 :   nsRect oldGroupVisualOverflow = GetVisualOverflowRect();
     858                 :   
     859               0 :   groupRect.height -= yGroupOffset;
     860               0 :   if (didCollapse) {
     861                 :     // add back the cellspacing between rowgroups
     862               0 :     groupRect.height += tableFrame->GetCellSpacingY();
     863                 :   }
     864                 : 
     865               0 :   groupRect.y -= aYTotalOffset;
     866               0 :   groupRect.width = aWidth;
     867                 : 
     868               0 :   if (aYTotalOffset != 0) {
     869               0 :     InvalidateFrameSubtree();
     870                 :   }
     871                 :   
     872               0 :   SetRect(groupRect);
     873               0 :   overflow.UnionAllWith(nsRect(0, 0, groupRect.width, groupRect.height));
     874               0 :   FinishAndStoreOverflow(overflow, nsSize(groupRect.width, groupRect.height));
     875               0 :   nsTableFrame::RePositionViews(this);
     876                 :   nsTableFrame::InvalidateFrame(this, oldGroupRect, oldGroupVisualOverflow,
     877               0 :                                 false);
     878                 : 
     879               0 :   return yGroupOffset;
     880                 : }
     881                 : 
     882                 : // Move a child that was skipped during a reflow.
     883                 : void
     884               0 : nsTableRowGroupFrame::SlideChild(nsRowGroupReflowState& aReflowState,
     885                 :                                  nsIFrame*              aKidFrame)
     886                 : {
     887                 :   // Move the frame if we need to
     888               0 :   nsPoint oldPosition = aKidFrame->GetPosition();
     889               0 :   nsPoint newPosition = oldPosition;
     890               0 :   newPosition.y = aReflowState.y;
     891               0 :   if (oldPosition.y != newPosition.y) {
     892               0 :     aKidFrame->InvalidateFrameSubtree();
     893               0 :     aKidFrame->SetPosition(newPosition);
     894               0 :     nsTableFrame::RePositionViews(aKidFrame);
     895               0 :     aKidFrame->InvalidateFrameSubtree();
     896                 :   }
     897               0 : }
     898                 : 
     899                 : // Create a continuing frame, add it to the child list, and then push it
     900                 : // and the frames that follow
     901                 : void 
     902               0 : nsTableRowGroupFrame::CreateContinuingRowFrame(nsPresContext& aPresContext,
     903                 :                                                nsIFrame&      aRowFrame,
     904                 :                                                nsIFrame**     aContRowFrame)
     905                 : {
     906                 :   // XXX what is the row index?
     907               0 :   if (!aContRowFrame) {NS_ASSERTION(false, "bad call"); return;}
     908                 :   // create the continuing frame which will create continuing cell frames
     909                 :   nsresult rv = aPresContext.PresShell()->FrameConstructor()->
     910               0 :     CreateContinuingFrame(&aPresContext, &aRowFrame, this, aContRowFrame);
     911               0 :   if (NS_FAILED(rv)) {
     912               0 :     *aContRowFrame = nsnull;
     913               0 :     return;
     914                 :   }
     915                 : 
     916                 :   // Add the continuing row frame to the child list
     917               0 :   mFrames.InsertFrame(nsnull, &aRowFrame, *aContRowFrame);
     918                 : 
     919                 :   // Push the continuing row frame and the frames that follow
     920               0 :   PushChildren(&aPresContext, *aContRowFrame, &aRowFrame);
     921                 : }
     922                 : 
     923                 : // Reflow the cells with rowspan > 1 which originate between aFirstRow
     924                 : // and end on or after aLastRow. aFirstTruncatedRow is the highest row on the
     925                 : // page that contains a cell which cannot split on this page 
     926                 : void
     927               0 : nsTableRowGroupFrame::SplitSpanningCells(nsPresContext&           aPresContext,
     928                 :                                          const nsHTMLReflowState& aReflowState,
     929                 :                                          nsTableFrame&            aTable,
     930                 :                                          nsTableRowFrame&         aFirstRow, 
     931                 :                                          nsTableRowFrame&         aLastRow,  
     932                 :                                          bool                     aFirstRowIsTopOfPage,
     933                 :                                          nscoord                  aSpanningRowBottom,
     934                 :                                          nsTableRowFrame*&        aContRow,
     935                 :                                          nsTableRowFrame*&        aFirstTruncatedRow,
     936                 :                                          nscoord&                 aDesiredHeight)
     937                 : {
     938               0 :   NS_ASSERTION(aSpanningRowBottom >= 0, "Can't split negative heights");
     939               0 :   aFirstTruncatedRow = nsnull;
     940               0 :   aDesiredHeight     = 0;
     941                 : 
     942               0 :   const bool borderCollapse = aTable.IsBorderCollapse();
     943               0 :   PRInt32 lastRowIndex = aLastRow.GetRowIndex();
     944               0 :   bool wasLast = false;
     945               0 :   bool haveRowSpan = false;
     946                 :   // Iterate the rows between aFirstRow and aLastRow
     947               0 :   for (nsTableRowFrame* row = &aFirstRow; !wasLast; row = row->GetNextRow()) {
     948               0 :     wasLast = (row == &aLastRow);
     949               0 :     PRInt32 rowIndex = row->GetRowIndex();
     950               0 :     nsPoint rowPos = row->GetPosition();
     951                 :     // Iterate the cells looking for those that have rowspan > 1
     952               0 :     for (nsTableCellFrame* cell = row->GetFirstCell(); cell; cell = cell->GetNextCell()) {
     953               0 :       PRInt32 rowSpan = aTable.GetEffectiveRowSpan(rowIndex, *cell);
     954                 :       // Only reflow rowspan > 1 cells which span aLastRow. Those which don't span aLastRow
     955                 :       // were reflowed correctly during the unconstrained height reflow. 
     956               0 :       if ((rowSpan > 1) && (rowIndex + rowSpan > lastRowIndex)) {
     957               0 :         haveRowSpan = true;
     958                 :         nsReflowStatus status;
     959                 :         // Ask the row to reflow the cell to the height of all the rows it spans up through aLastRow
     960                 :         // aAvailHeight is the space between the row group start and the end of the page
     961               0 :         nscoord cellAvailHeight = aSpanningRowBottom - rowPos.y;
     962               0 :         NS_ASSERTION(cellAvailHeight >= 0, "No space for cell?");
     963               0 :         bool isTopOfPage = (row == &aFirstRow) && aFirstRowIsTopOfPage;
     964                 : 
     965               0 :         nsRect rowRect = row->GetRect();
     966                 :         nsSize rowAvailSize(aReflowState.availableWidth,
     967                 :                             NS_MAX(aReflowState.availableHeight - rowRect.y,
     968               0 :                                    0));
     969                 :         // don't let the available height exceed what
     970                 :         // CalculateRowHeights set for it
     971               0 :         rowAvailSize.height = NS_MIN(rowAvailSize.height, rowRect.height);
     972                 :         nsHTMLReflowState rowReflowState(&aPresContext, aReflowState,
     973                 :                                          row, rowAvailSize,
     974               0 :                                          -1, -1, false);
     975               0 :         InitChildReflowState(aPresContext, borderCollapse, rowReflowState);
     976               0 :         rowReflowState.mFlags.mIsTopOfPage = isTopOfPage; // set top of page
     977                 : 
     978                 :         nscoord cellHeight = row->ReflowCellFrame(&aPresContext, rowReflowState,
     979                 :                                                   isTopOfPage, cell,
     980               0 :                                                   cellAvailHeight, status);
     981               0 :         aDesiredHeight = NS_MAX(aDesiredHeight, rowPos.y + cellHeight);
     982               0 :         if (NS_FRAME_IS_COMPLETE(status)) {
     983               0 :           if (cellHeight > cellAvailHeight) {
     984               0 :             aFirstTruncatedRow = row;
     985               0 :             if ((row != &aFirstRow) || !aFirstRowIsTopOfPage) {
     986                 :               // return now, since we will be getting another reflow after either (1) row is 
     987                 :               // moved to the next page or (2) the row group is moved to the next page
     988                 :               return;
     989                 :             }
     990                 :           }
     991                 :         }
     992                 :         else {
     993               0 :           if (!aContRow) {
     994               0 :             CreateContinuingRowFrame(aPresContext, aLastRow, (nsIFrame**)&aContRow);
     995                 :           }
     996               0 :           if (aContRow) {
     997               0 :             if (row != &aLastRow) {
     998                 :               // aContRow needs a continuation for cell, since cell spanned into aLastRow 
     999                 :               // but does not originate there
    1000               0 :               nsTableCellFrame* contCell = nsnull;
    1001                 :               aPresContext.PresShell()->FrameConstructor()->
    1002                 :                 CreateContinuingFrame(&aPresContext, cell, &aLastRow,
    1003               0 :                                       (nsIFrame**)&contCell);
    1004                 :               PRInt32 colIndex;
    1005               0 :               cell->GetColIndex(colIndex);
    1006               0 :               aContRow->InsertCellFrame(contCell, colIndex);
    1007                 :             }
    1008                 :           }
    1009                 :         }
    1010                 :       }
    1011                 :     }
    1012                 :   }
    1013               0 :   if (!haveRowSpan) {
    1014               0 :     aDesiredHeight = aLastRow.GetRect().YMost();
    1015                 :   }
    1016                 : }
    1017                 : 
    1018                 : // Remove the next-in-flow of the row, its cells and their cell blocks. This 
    1019                 : // is necessary in case the row doesn't need a continuation later on or needs 
    1020                 : // a continuation which doesn't have the same number of cells that now exist. 
    1021                 : void
    1022               0 : nsTableRowGroupFrame::UndoContinuedRow(nsPresContext*   aPresContext,
    1023                 :                                        nsTableRowFrame* aRow)
    1024                 : {
    1025               0 :   if (!aRow) return; // allow null aRow to avoid callers doing null checks
    1026                 : 
    1027                 :   // rowBefore was the prev-sibling of aRow's next-sibling before aRow was created
    1028               0 :   nsTableRowFrame* rowBefore = (nsTableRowFrame*)aRow->GetPrevInFlow();
    1029               0 :   NS_PRECONDITION(mFrames.ContainsFrame(rowBefore),
    1030                 :                   "rowBefore not in our frame list?");
    1031                 : 
    1032               0 :   nsAutoPtr<nsFrameList> overflows(StealOverflowFrames());
    1033               0 :   if (!rowBefore || !overflows || overflows->IsEmpty() ||
    1034               0 :       overflows->FirstChild() != aRow) {
    1035               0 :     NS_ERROR("invalid continued row");
    1036                 :     return;
    1037                 :   }
    1038                 : 
    1039                 :   // Destroy aRow, its cells, and their cell blocks. Cell blocks that have split
    1040                 :   // will not have reflowed yet to pick up content from any overflow lines.
    1041               0 :   overflows->DestroyFrame(aRow);
    1042                 : 
    1043               0 :   if (overflows->IsEmpty())
    1044                 :     return;
    1045                 :   // Put the overflow rows into our child list
    1046               0 :   mFrames.InsertFrames(nsnull, rowBefore, *overflows);
    1047                 : }
    1048                 : 
    1049                 : static nsTableRowFrame* 
    1050               0 : GetRowBefore(nsTableRowFrame& aStartRow,
    1051                 :              nsTableRowFrame& aRow)
    1052                 : {
    1053               0 :   nsTableRowFrame* rowBefore = nsnull;
    1054               0 :   for (nsTableRowFrame* sib = &aStartRow; sib && (sib != &aRow); sib = sib->GetNextRow()) {
    1055               0 :     rowBefore = sib;
    1056                 :   }
    1057               0 :   return rowBefore;
    1058                 : }
    1059                 : 
    1060                 : nsresult
    1061               0 : nsTableRowGroupFrame::SplitRowGroup(nsPresContext*           aPresContext,
    1062                 :                                     nsHTMLReflowMetrics&     aDesiredSize,
    1063                 :                                     const nsHTMLReflowState& aReflowState,
    1064                 :                                     nsTableFrame*            aTableFrame,
    1065                 :                                     nsReflowStatus&          aStatus)
    1066                 : {
    1067               0 :   NS_PRECONDITION(aPresContext->IsPaginated(), "SplitRowGroup currently supports only paged media"); 
    1068                 : 
    1069               0 :   nsresult rv = NS_OK;
    1070               0 :   nsTableRowFrame* prevRowFrame = nsnull;
    1071               0 :   aDesiredSize.height = 0;
    1072                 : 
    1073               0 :   nscoord availWidth  = aReflowState.availableWidth;
    1074               0 :   nscoord availHeight = aReflowState.availableHeight;
    1075                 :   
    1076               0 :   const bool borderCollapse = aTableFrame->IsBorderCollapse();
    1077               0 :   nscoord cellSpacingY = aTableFrame->GetCellSpacingY();
    1078                 :   
    1079                 :   // get the page height
    1080               0 :   nscoord pageHeight = aPresContext->GetPageSize().height;
    1081               0 :   NS_ASSERTION(pageHeight != NS_UNCONSTRAINEDSIZE, 
    1082                 :                "The table shouldn't be split when there should be space");
    1083                 : 
    1084               0 :   bool isTopOfPage = aReflowState.mFlags.mIsTopOfPage;
    1085               0 :   nsTableRowFrame* firstRowThisPage = GetFirstRow();
    1086                 : 
    1087                 :   // Need to dirty the table's geometry, or else the row might skip
    1088                 :   // reflowing its cell as an optimization.
    1089               0 :   aTableFrame->SetGeometryDirty();
    1090                 : 
    1091                 :   // Walk each of the row frames looking for the first row frame that doesn't fit 
    1092                 :   // in the available space
    1093               0 :   for (nsTableRowFrame* rowFrame = firstRowThisPage; rowFrame; rowFrame = rowFrame->GetNextRow()) {
    1094               0 :     bool rowIsOnPage = true;
    1095               0 :     nsRect rowRect = rowFrame->GetRect();
    1096                 :     // See if the row fits on this page
    1097               0 :     if (rowRect.YMost() > availHeight) {
    1098               0 :       nsTableRowFrame* contRow = nsnull;
    1099                 :       // Reflow the row in the availabe space and have it split if it is the 1st
    1100                 :       // row (on the page) or there is at least 5% of the current page available 
    1101                 :       // XXX this 5% should be made a preference 
    1102               0 :       if (!prevRowFrame || (availHeight - aDesiredSize.height > pageHeight / 20)) { 
    1103               0 :         nsSize availSize(availWidth, NS_MAX(availHeight - rowRect.y, 0));
    1104                 :         // don't let the available height exceed what CalculateRowHeights set for it
    1105               0 :         availSize.height = NS_MIN(availSize.height, rowRect.height);
    1106                 : 
    1107                 :         nsHTMLReflowState rowReflowState(aPresContext, aReflowState,
    1108                 :                                          rowFrame, availSize,
    1109               0 :                                          -1, -1, false);
    1110                 :                                          
    1111               0 :         InitChildReflowState(*aPresContext, borderCollapse, rowReflowState);
    1112               0 :         rowReflowState.mFlags.mIsTopOfPage = isTopOfPage; // set top of page
    1113               0 :         nsHTMLReflowMetrics rowMetrics;
    1114                 : 
    1115                 :         // Get the old size before we reflow.
    1116               0 :         nsRect oldRowRect = rowFrame->GetRect();
    1117               0 :         nsRect oldRowVisualOverflow = rowFrame->GetVisualOverflowRect();
    1118                 : 
    1119                 :         // Reflow the cell with the constrained height. A cell with rowspan >1 will get this
    1120                 :         // reflow later during SplitSpanningCells.
    1121                 :         rv = ReflowChild(rowFrame, aPresContext, rowMetrics, rowReflowState,
    1122               0 :                          0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus);
    1123               0 :         if (NS_FAILED(rv)) return rv;
    1124               0 :         rowFrame->SetSize(nsSize(rowMetrics.width, rowMetrics.height));
    1125               0 :         rowFrame->DidReflow(aPresContext, nsnull, NS_FRAME_REFLOW_FINISHED);
    1126               0 :         rowFrame->DidResize();
    1127                 : 
    1128                 :         nsTableFrame::InvalidateFrame(rowFrame, oldRowRect,
    1129                 :                                       oldRowVisualOverflow,
    1130               0 :                                       false);
    1131                 : 
    1132               0 :         if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
    1133                 :           // The row frame is incomplete and all of the rowspan 1 cells' block frames split
    1134               0 :           if ((rowMetrics.height <= rowReflowState.availableHeight) || isTopOfPage) {
    1135                 :             // The row stays on this page because either it split ok or we're on the top of page.
    1136                 :             // If top of page and the height exceeded the avail height, then there will be data loss
    1137               0 :             NS_ASSERTION(rowMetrics.height <= rowReflowState.availableHeight, 
    1138                 :                          "data loss - incomplete row needed more height than available, on top of page");
    1139               0 :             CreateContinuingRowFrame(*aPresContext, *rowFrame, (nsIFrame**)&contRow);
    1140               0 :             if (contRow) {
    1141               0 :               aDesiredSize.height += rowMetrics.height;
    1142               0 :               if (prevRowFrame) 
    1143               0 :                 aDesiredSize.height += cellSpacingY;
    1144                 :             }
    1145               0 :             else return NS_ERROR_NULL_POINTER;
    1146                 :           }
    1147                 :           else {
    1148                 :             // Put the row on the next page to give it more height 
    1149               0 :             rowIsOnPage = false;
    1150                 :           }
    1151                 :         } 
    1152                 :         else {
    1153                 :           // The row frame is complete because either (1) its minimum height is greater than the 
    1154                 :           // available height we gave it, or (2) it may have been given a larger height through 
    1155                 :           // style than its content, or (3) it contains a rowspan >1 cell which hasn't been
    1156                 :           // reflowed with a constrained height yet (we will find out when SplitSpanningCells is
    1157                 :           // called below)
    1158               0 :           if (rowMetrics.height > availSize.height) {
    1159                 :             // cases (1) and (2)
    1160               0 :             if (isTopOfPage) { 
    1161                 :               // We're on top of the page, so keep the row on this page. There will be data loss.
    1162                 :               // Push the row frame that follows
    1163               0 :               nsTableRowFrame* nextRowFrame = rowFrame->GetNextRow();
    1164               0 :               if (nextRowFrame) {
    1165               0 :                 aStatus = NS_FRAME_NOT_COMPLETE;
    1166                 :               }
    1167               0 :               aDesiredSize.height += rowMetrics.height;
    1168               0 :               if (prevRowFrame) 
    1169               0 :                 aDesiredSize.height += cellSpacingY;
    1170               0 :               NS_WARNING("data loss - complete row needed more height than available, on top of page");
    1171                 :             }
    1172                 :             else {
    1173                 :               // We're not on top of the page, so put the row on the next page to give it more height 
    1174               0 :               rowIsOnPage = false;
    1175                 :             }
    1176                 :           }
    1177               0 :         }
    1178                 :       } //if (!prevRowFrame || (availHeight - aDesiredSize.height > pageHeight / 20))
    1179                 :       else { 
    1180                 :         // put the row on the next page to give it more height
    1181               0 :         rowIsOnPage = false;
    1182                 :       }
    1183                 : 
    1184               0 :       nsTableRowFrame* lastRowThisPage = rowFrame;
    1185               0 :       nscoord spanningRowBottom = availHeight;
    1186               0 :       if (!rowIsOnPage) {
    1187               0 :         NS_ASSERTION(!contRow, "We should not have created a continuation if none of this row fits");
    1188               0 :         if (prevRowFrame) {
    1189               0 :           spanningRowBottom = prevRowFrame->GetRect().YMost();
    1190               0 :           lastRowThisPage = prevRowFrame;
    1191               0 :           isTopOfPage = (lastRowThisPage == firstRowThisPage) && aReflowState.mFlags.mIsTopOfPage;
    1192               0 :           aStatus = NS_FRAME_NOT_COMPLETE;
    1193                 :         }
    1194                 :         else {
    1195                 :           // We can't push children, so let our parent reflow us again with more space
    1196               0 :           aDesiredSize.height = rowRect.YMost();
    1197               0 :           aStatus = NS_FRAME_COMPLETE;
    1198                 :           break;
    1199                 :         }
    1200                 :       }
    1201                 :       // reflow the cells with rowspan >1 that occur on the page
    1202                 : 
    1203                 :       nsTableRowFrame* firstTruncatedRow;
    1204                 :       nscoord yMost;
    1205                 :       SplitSpanningCells(*aPresContext, aReflowState, *aTableFrame, *firstRowThisPage,
    1206                 :                          *lastRowThisPage, aReflowState.mFlags.mIsTopOfPage, spanningRowBottom, contRow, 
    1207               0 :                          firstTruncatedRow, yMost);
    1208               0 :       if (firstTruncatedRow) {
    1209                 :         // A rowspan >1 cell did not fit (and could not split) in the space we gave it
    1210               0 :         if (firstTruncatedRow == firstRowThisPage) {
    1211               0 :           if (aReflowState.mFlags.mIsTopOfPage) {
    1212               0 :             NS_WARNING("data loss in a row spanned cell");
    1213                 :           }
    1214                 :           else {
    1215                 :             // We can't push children, so let our parent reflow us again with more space
    1216               0 :             aDesiredSize.height = rowRect.YMost();
    1217               0 :             aStatus = NS_FRAME_COMPLETE;
    1218               0 :             UndoContinuedRow(aPresContext, contRow);
    1219               0 :             contRow = nsnull;
    1220                 :           }
    1221                 :         }
    1222                 :         else { // (firstTruncatedRow != firstRowThisPage)
    1223                 :           // Try to put firstTruncateRow on the next page 
    1224               0 :           nsTableRowFrame* rowBefore = ::GetRowBefore(*firstRowThisPage, *firstTruncatedRow);
    1225               0 :           nscoord oldSpanningRowBottom = spanningRowBottom;
    1226               0 :           spanningRowBottom = rowBefore->GetRect().YMost();
    1227                 : 
    1228               0 :           UndoContinuedRow(aPresContext, contRow);
    1229               0 :           contRow = nsnull;
    1230               0 :           nsTableRowFrame* oldLastRowThisPage = lastRowThisPage;
    1231               0 :           lastRowThisPage = rowBefore;
    1232               0 :           aStatus = NS_FRAME_NOT_COMPLETE;
    1233                 : 
    1234                 :           // Call SplitSpanningCells again with rowBefore as the last row on the page
    1235                 :           SplitSpanningCells(*aPresContext, aReflowState, *aTableFrame, 
    1236                 :                              *firstRowThisPage, *rowBefore, aReflowState.mFlags.mIsTopOfPage, 
    1237               0 :                              spanningRowBottom, contRow, firstTruncatedRow, aDesiredSize.height);
    1238               0 :           if (firstTruncatedRow) {
    1239               0 :             if (aReflowState.mFlags.mIsTopOfPage) {
    1240                 :               // We were better off with the 1st call to SplitSpanningCells, do it again
    1241               0 :               UndoContinuedRow(aPresContext, contRow);
    1242               0 :               contRow = nsnull;
    1243               0 :               lastRowThisPage = oldLastRowThisPage;
    1244               0 :               spanningRowBottom = oldSpanningRowBottom;
    1245                 :               SplitSpanningCells(*aPresContext, aReflowState, *aTableFrame, *firstRowThisPage,
    1246                 :                                  *lastRowThisPage, aReflowState.mFlags.mIsTopOfPage, spanningRowBottom, contRow, 
    1247               0 :                                  firstTruncatedRow, aDesiredSize.height);
    1248               0 :               NS_WARNING("data loss in a row spanned cell");
    1249                 :             }
    1250                 :             else {
    1251                 :               // Let our parent reflow us again with more space
    1252               0 :               aDesiredSize.height = rowRect.YMost();
    1253               0 :               aStatus = NS_FRAME_COMPLETE;
    1254               0 :               UndoContinuedRow(aPresContext, contRow);
    1255               0 :               contRow = nsnull;
    1256                 :             }
    1257                 :           }
    1258                 :         } // if (firstTruncatedRow == firstRowThisPage)
    1259                 :       } // if (firstTruncatedRow)
    1260                 :       else {
    1261               0 :         aDesiredSize.height = NS_MAX(aDesiredSize.height, yMost);
    1262               0 :         if (contRow) {
    1263               0 :           aStatus = NS_FRAME_NOT_COMPLETE;
    1264                 :         }
    1265                 :       }
    1266               0 :       if (NS_FRAME_IS_NOT_COMPLETE(aStatus) && !contRow) {
    1267               0 :         nsTableRowFrame* nextRow = lastRowThisPage->GetNextRow();
    1268               0 :         if (nextRow) {
    1269               0 :           PushChildren(aPresContext, nextRow, lastRowThisPage);
    1270                 :         }
    1271                 :       }
    1272                 :       break;
    1273                 :     } // if (rowRect.YMost() > availHeight)
    1274                 :     else { 
    1275               0 :       aDesiredSize.height = rowRect.YMost();
    1276               0 :       prevRowFrame = rowFrame;
    1277                 :       // see if there is a page break after the row
    1278               0 :       nsTableRowFrame* nextRow = rowFrame->GetNextRow();
    1279               0 :       if (nextRow && nsTableFrame::PageBreakAfter(rowFrame, nextRow)) {
    1280               0 :         PushChildren(aPresContext, nextRow, rowFrame);
    1281               0 :         aStatus = NS_FRAME_NOT_COMPLETE;
    1282                 :         break;
    1283                 :       }
    1284                 :     }
    1285                 :     // after the 1st row that has a height, we can't be on top
    1286                 :     // of the page anymore.
    1287               0 :     isTopOfPage = isTopOfPage && rowRect.YMost() == 0;
    1288                 :   }
    1289               0 :   return NS_OK;
    1290                 : }
    1291                 : 
    1292                 : /** Layout the entire row group.
    1293                 :   * This method stacks rows vertically according to HTML 4.0 rules.
    1294                 :   * Rows are responsible for layout of their children.
    1295                 :   */
    1296                 : NS_METHOD
    1297               0 : nsTableRowGroupFrame::Reflow(nsPresContext*           aPresContext,
    1298                 :                              nsHTMLReflowMetrics&     aDesiredSize,
    1299                 :                              const nsHTMLReflowState& aReflowState,
    1300                 :                              nsReflowStatus&          aStatus)
    1301                 : {
    1302               0 :   DO_GLOBAL_REFLOW_COUNT("nsTableRowGroupFrame");
    1303               0 :   DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
    1304                 : 
    1305               0 :   nsresult rv = NS_OK;
    1306               0 :   aStatus     = NS_FRAME_COMPLETE;
    1307                 : 
    1308                 :   // Row geometry may be going to change so we need to invalidate any row cursor.
    1309               0 :   ClearRowCursor();
    1310                 : 
    1311                 :   // see if a special height reflow needs to occur due to having a pct height
    1312               0 :   nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState);
    1313                 : 
    1314               0 :   nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
    1315               0 :   nsRowGroupReflowState state(aReflowState, tableFrame);
    1316               0 :   const nsStyleVisibility* groupVis = GetStyleVisibility();
    1317               0 :   bool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE == groupVis->mVisible);
    1318               0 :   if (collapseGroup) {
    1319               0 :     tableFrame->SetNeedToCollapse(true);
    1320                 :   }
    1321                 : 
    1322                 :   // Check for an overflow list
    1323               0 :   MoveOverflowToChildList(aPresContext);
    1324                 : 
    1325                 :   // Reflow the existing frames. 
    1326               0 :   bool splitDueToPageBreak = false;
    1327                 :   rv = ReflowChildren(aPresContext, aDesiredSize, state, aStatus,
    1328               0 :                       &splitDueToPageBreak);
    1329                 : 
    1330                 :   // See if all the frames fit. Do not try to split anything if we're
    1331                 :   // not paginated ... we can't split across columns yet.
    1332               0 :   if (aReflowState.mFlags.mTableIsSplittable &&
    1333                 :       NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight &&
    1334                 :       (NS_FRAME_NOT_COMPLETE == aStatus || splitDueToPageBreak || 
    1335                 :        aDesiredSize.height > aReflowState.availableHeight)) {
    1336                 :     // Nope, find a place to split the row group 
    1337               0 :     bool specialReflow = (bool)aReflowState.mFlags.mSpecialHeightReflow;
    1338               0 :     ((nsHTMLReflowState::ReflowStateFlags&)aReflowState.mFlags).mSpecialHeightReflow = false;
    1339                 : 
    1340               0 :     SplitRowGroup(aPresContext, aDesiredSize, aReflowState, tableFrame, aStatus);
    1341                 : 
    1342               0 :     ((nsHTMLReflowState::ReflowStateFlags&)aReflowState.mFlags).mSpecialHeightReflow = specialReflow;
    1343                 :   }
    1344                 : 
    1345                 :   // If we have a next-in-flow, then we're not complete
    1346                 :   // XXXldb This used to be done only for the incremental reflow codepath.
    1347               0 :   if (GetNextInFlow()) {
    1348               0 :     aStatus = NS_FRAME_NOT_COMPLETE;
    1349                 :   }
    1350                 : 
    1351               0 :   SetHasStyleHeight((NS_UNCONSTRAINEDSIZE != aReflowState.ComputedHeight()) &&
    1352               0 :                     (aReflowState.ComputedHeight() > 0)); 
    1353                 :   
    1354                 :   // just set our width to what was available. The table will calculate the width and not use our value.
    1355               0 :   aDesiredSize.width = aReflowState.availableWidth;
    1356                 : 
    1357               0 :   aDesiredSize.UnionOverflowAreasWithDesiredBounds();
    1358                 : 
    1359                 :   // If our parent is in initial reflow, it'll handle invalidating our
    1360                 :   // entire overflow rect.
    1361               0 :   if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
    1362               0 :     CheckInvalidateSizeChange(aDesiredSize);
    1363                 :   }
    1364                 :   
    1365               0 :   FinishAndStoreOverflow(&aDesiredSize);
    1366               0 :   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
    1367               0 :   return rv;
    1368                 : }
    1369                 : 
    1370                 : /* virtual */ void
    1371               0 : nsTableRowGroupFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
    1372                 : {
    1373               0 :   if (!aOldStyleContext) //avoid this on init
    1374               0 :     return;
    1375                 :      
    1376               0 :   nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
    1377               0 :   if (tableFrame->IsBorderCollapse() &&
    1378               0 :       tableFrame->BCRecalcNeeded(aOldStyleContext, GetStyleContext())) {
    1379                 :     nsIntRect damageArea(0, GetStartRowIndex(), tableFrame->GetColCount(),
    1380               0 :                          GetRowCount());
    1381               0 :     tableFrame->AddBCDamageArea(damageArea);
    1382                 :   }
    1383                 : }
    1384                 : 
    1385                 : NS_IMETHODIMP
    1386               0 : nsTableRowGroupFrame::AppendFrames(ChildListID     aListID,
    1387                 :                                    nsFrameList&    aFrameList)
    1388                 : {
    1389               0 :   NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
    1390                 : 
    1391               0 :   ClearRowCursor();
    1392                 : 
    1393                 :   // collect the new row frames in an array
    1394                 :   // XXXbz why are we doing the QI stuff?  There shouldn't be any non-rows here.
    1395               0 :   nsAutoTArray<nsTableRowFrame*, 8> rows;
    1396               0 :   for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
    1397               0 :     nsTableRowFrame *rowFrame = do_QueryFrame(e.get());
    1398               0 :     NS_ASSERTION(rowFrame, "Unexpected frame; frame constructor screwed up");
    1399               0 :     if (rowFrame) {
    1400               0 :       NS_ASSERTION(NS_STYLE_DISPLAY_TABLE_ROW ==
    1401                 :                      e.get()->GetStyleDisplay()->mDisplay,
    1402                 :                    "wrong display type on rowframe");      
    1403               0 :       rows.AppendElement(rowFrame);
    1404                 :     }
    1405                 :   }
    1406                 : 
    1407               0 :   PRInt32 rowIndex = GetRowCount();
    1408                 :   // Append the frames to the sibling chain
    1409               0 :   mFrames.AppendFrames(nsnull, aFrameList);
    1410                 : 
    1411               0 :   if (rows.Length() > 0) {
    1412               0 :     nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
    1413               0 :     tableFrame->AppendRows(this, rowIndex, rows);
    1414               0 :     PresContext()->PresShell()->
    1415                 :       FrameNeedsReflow(this, nsIPresShell::eTreeChange,
    1416               0 :                        NS_FRAME_HAS_DIRTY_CHILDREN);
    1417               0 :     tableFrame->SetGeometryDirty();
    1418                 :   }
    1419                 : 
    1420               0 :   return NS_OK;
    1421                 : }
    1422                 : 
    1423                 : NS_IMETHODIMP
    1424               0 : nsTableRowGroupFrame::InsertFrames(ChildListID     aListID,
    1425                 :                                    nsIFrame*       aPrevFrame,
    1426                 :                                    nsFrameList&    aFrameList)
    1427                 : {
    1428               0 :   NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
    1429               0 :   NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
    1430                 :                "inserting after sibling frame with different parent");
    1431                 : 
    1432               0 :   ClearRowCursor();
    1433                 : 
    1434                 :   // collect the new row frames in an array
    1435                 :   // XXXbz why are we doing the QI stuff?  There shouldn't be any non-rows here.
    1436               0 :   nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
    1437               0 :   nsTArray<nsTableRowFrame*> rows;
    1438               0 :   bool gotFirstRow = false;
    1439               0 :   for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
    1440               0 :     nsTableRowFrame *rowFrame = do_QueryFrame(e.get());
    1441               0 :     NS_ASSERTION(rowFrame, "Unexpected frame; frame constructor screwed up");
    1442               0 :     if (rowFrame) {
    1443               0 :       NS_ASSERTION(NS_STYLE_DISPLAY_TABLE_ROW ==
    1444                 :                      e.get()->GetStyleDisplay()->mDisplay,
    1445                 :                    "wrong display type on rowframe");      
    1446               0 :       rows.AppendElement(rowFrame);
    1447               0 :       if (!gotFirstRow) {
    1448               0 :         rowFrame->SetFirstInserted(true);
    1449               0 :         gotFirstRow = true;
    1450               0 :         tableFrame->SetRowInserted(true);
    1451                 :       }
    1452                 :     }
    1453                 :   }
    1454                 : 
    1455               0 :   PRInt32 startRowIndex = GetStartRowIndex();
    1456                 :   // Insert the frames in the sibling chain
    1457               0 :   mFrames.InsertFrames(nsnull, aPrevFrame, aFrameList);
    1458                 : 
    1459               0 :   PRInt32 numRows = rows.Length();
    1460               0 :   if (numRows > 0) {
    1461               0 :     nsTableRowFrame* prevRow = (nsTableRowFrame *)nsTableFrame::GetFrameAtOrBefore(this, aPrevFrame, nsGkAtoms::tableRowFrame);
    1462               0 :     PRInt32 rowIndex = (prevRow) ? prevRow->GetRowIndex() + 1 : startRowIndex;
    1463               0 :     tableFrame->InsertRows(this, rows, rowIndex, true);
    1464                 : 
    1465               0 :     PresContext()->PresShell()->
    1466                 :       FrameNeedsReflow(this, nsIPresShell::eTreeChange,
    1467               0 :                        NS_FRAME_HAS_DIRTY_CHILDREN);
    1468               0 :     tableFrame->SetGeometryDirty();
    1469                 :   }
    1470               0 :   return NS_OK;
    1471                 : }
    1472                 : 
    1473                 : NS_IMETHODIMP
    1474               0 : nsTableRowGroupFrame::RemoveFrame(ChildListID     aListID,
    1475                 :                                   nsIFrame*       aOldFrame)
    1476                 : {
    1477               0 :   NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
    1478                 : 
    1479               0 :   ClearRowCursor();
    1480                 : 
    1481               0 :   nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
    1482                 :   // XXX why are we doing the QI stuff?  There shouldn't be any non-rows here.
    1483               0 :   nsTableRowFrame* rowFrame = do_QueryFrame(aOldFrame);
    1484               0 :   if (rowFrame) {
    1485                 :     // remove the rows from the table (and flag a rebalance)
    1486               0 :     tableFrame->RemoveRows(*rowFrame, 1, true);
    1487                 : 
    1488               0 :     PresContext()->PresShell()->
    1489                 :       FrameNeedsReflow(this, nsIPresShell::eTreeChange,
    1490               0 :                        NS_FRAME_HAS_DIRTY_CHILDREN);
    1491               0 :     tableFrame->SetGeometryDirty();
    1492                 :   }
    1493               0 :   mFrames.DestroyFrame(aOldFrame);
    1494                 : 
    1495               0 :   return NS_OK;
    1496                 : }
    1497                 : 
    1498                 : /* virtual */ nsMargin
    1499               0 : nsTableRowGroupFrame::GetUsedMargin() const
    1500                 : {
    1501               0 :   return nsMargin(0,0,0,0);
    1502                 : }
    1503                 : 
    1504                 : /* virtual */ nsMargin
    1505               0 : nsTableRowGroupFrame::GetUsedBorder() const
    1506                 : {
    1507               0 :   return nsMargin(0,0,0,0);
    1508                 : }
    1509                 : 
    1510                 : /* virtual */ nsMargin
    1511               0 : nsTableRowGroupFrame::GetUsedPadding() const
    1512                 : {
    1513               0 :   return nsMargin(0,0,0,0);
    1514                 : }
    1515                 : 
    1516                 : nscoord 
    1517               0 : nsTableRowGroupFrame::GetHeightBasis(const nsHTMLReflowState& aReflowState)
    1518                 : {
    1519               0 :   nscoord result = 0;
    1520               0 :   nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
    1521               0 :   if ((aReflowState.ComputedHeight() > 0) && (aReflowState.ComputedHeight() < NS_UNCONSTRAINEDSIZE)) {
    1522               0 :     nscoord cellSpacing = NS_MAX(0, GetRowCount() - 1) * tableFrame->GetCellSpacingY();
    1523               0 :     result = aReflowState.ComputedHeight() - cellSpacing;
    1524                 :   }
    1525                 :   else {
    1526               0 :     const nsHTMLReflowState* parentRS = aReflowState.parentReflowState;
    1527               0 :     if (parentRS && (tableFrame != parentRS->frame)) {
    1528               0 :       parentRS = parentRS->parentReflowState;
    1529                 :     }
    1530               0 :     if (parentRS && (tableFrame == parentRS->frame) && 
    1531               0 :         (parentRS->ComputedHeight() > 0) && (parentRS->ComputedHeight() < NS_UNCONSTRAINEDSIZE)) {
    1532               0 :       nscoord cellSpacing = NS_MAX(0, tableFrame->GetRowCount() + 1) * tableFrame->GetCellSpacingY();
    1533               0 :       result = parentRS->ComputedHeight() - cellSpacing;
    1534                 :     }
    1535                 :   }
    1536                 : 
    1537               0 :   return result;
    1538                 : }
    1539                 : 
    1540                 : bool
    1541               0 : nsTableRowGroupFrame::IsSimpleRowFrame(nsTableFrame* aTableFrame,
    1542                 :                                        nsIFrame*     aFrame)
    1543                 : {
    1544                 :   // Make sure it's a row frame and not a row group frame
    1545               0 :   nsTableRowFrame *rowFrame = do_QueryFrame(aFrame);
    1546               0 :   if (rowFrame) {
    1547               0 :     PRInt32 rowIndex = rowFrame->GetRowIndex();
    1548                 :     
    1549                 :     // It's a simple row frame if there are no cells that span into or
    1550                 :     // across the row
    1551               0 :     PRInt32 numEffCols = aTableFrame->GetEffectiveColCount();
    1552               0 :     if (!aTableFrame->RowIsSpannedInto(rowIndex, numEffCols) &&
    1553               0 :         !aTableFrame->RowHasSpanningCells(rowIndex, numEffCols)) {
    1554               0 :       return true;
    1555                 :     }
    1556                 :   }
    1557                 : 
    1558               0 :   return false;
    1559                 : }
    1560                 : 
    1561                 : nsIAtom*
    1562               0 : nsTableRowGroupFrame::GetType() const
    1563                 : {
    1564               0 :   return nsGkAtoms::tableRowGroupFrame;
    1565                 : }
    1566                 : 
    1567                 : /** find page break before the first row **/
    1568                 : bool 
    1569               0 : nsTableRowGroupFrame::HasInternalBreakBefore() const
    1570                 : {
    1571               0 :  nsIFrame* firstChild = mFrames.FirstChild(); 
    1572               0 :   if (!firstChild)
    1573               0 :     return false;
    1574               0 :   return firstChild->GetStyleDisplay()->mBreakBefore;
    1575                 : }
    1576                 : 
    1577                 : /** find page break after the last row **/
    1578                 : bool 
    1579               0 : nsTableRowGroupFrame::HasInternalBreakAfter() const
    1580                 : {
    1581               0 :   nsIFrame* lastChild = mFrames.LastChild(); 
    1582               0 :   if (!lastChild)
    1583               0 :     return false;
    1584               0 :   return lastChild->GetStyleDisplay()->mBreakAfter;
    1585                 : }
    1586                 : /* ----- global methods ----- */
    1587                 : 
    1588                 : nsIFrame*
    1589               0 : NS_NewTableRowGroupFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
    1590                 : {
    1591               0 :   return new (aPresShell) nsTableRowGroupFrame(aContext);
    1592                 : }
    1593                 : 
    1594               0 : NS_IMPL_FRAMEARENA_HELPERS(nsTableRowGroupFrame)
    1595                 : 
    1596                 : #ifdef DEBUG
    1597                 : NS_IMETHODIMP
    1598               0 : nsTableRowGroupFrame::GetFrameName(nsAString& aResult) const
    1599                 : {
    1600               0 :   return MakeFrameName(NS_LITERAL_STRING("TableRowGroup"), aResult);
    1601                 : }
    1602                 : #endif
    1603                 : 
    1604                 : nsMargin* 
    1605               0 : nsTableRowGroupFrame::GetBCBorderWidth(nsMargin& aBorder)
    1606                 : {
    1607               0 :   aBorder.left = aBorder.right = aBorder.top = aBorder.bottom = 0;
    1608                 : 
    1609               0 :   nsTableRowFrame* firstRowFrame = nsnull;
    1610               0 :   nsTableRowFrame* lastRowFrame = nsnull;
    1611               0 :   for (nsTableRowFrame* rowFrame = GetFirstRow(); rowFrame; rowFrame = rowFrame->GetNextRow()) {
    1612               0 :     if (!firstRowFrame) {
    1613               0 :       firstRowFrame = rowFrame;
    1614                 :     }
    1615               0 :     lastRowFrame = rowFrame;
    1616                 :   }
    1617               0 :   if (firstRowFrame) {
    1618               0 :     aBorder.top    = nsPresContext::CSSPixelsToAppUnits(firstRowFrame->GetTopBCBorderWidth());
    1619               0 :     aBorder.bottom = nsPresContext::CSSPixelsToAppUnits(lastRowFrame->GetBottomBCBorderWidth());
    1620                 :   }
    1621                 : 
    1622               0 :   return &aBorder;
    1623                 : }
    1624                 : 
    1625               0 : void nsTableRowGroupFrame::SetContinuousBCBorderWidth(PRUint8     aForSide,
    1626                 :                                                       BCPixelSize aPixelValue)
    1627                 : {
    1628               0 :   switch (aForSide) {
    1629                 :     case NS_SIDE_RIGHT:
    1630               0 :       mRightContBorderWidth = aPixelValue;
    1631               0 :       return;
    1632                 :     case NS_SIDE_BOTTOM:
    1633               0 :       mBottomContBorderWidth = aPixelValue;
    1634               0 :       return;
    1635                 :     case NS_SIDE_LEFT:
    1636               0 :       mLeftContBorderWidth = aPixelValue;
    1637               0 :       return;
    1638                 :     default:
    1639               0 :       NS_ERROR("invalid NS_SIDE argument");
    1640                 :   }
    1641                 : }
    1642                 : 
    1643                 : //nsILineIterator methods
    1644                 : PRInt32
    1645               0 : nsTableRowGroupFrame::GetNumLines()
    1646                 : {
    1647               0 :   return GetRowCount();
    1648                 : }
    1649                 : 
    1650                 : bool
    1651               0 : nsTableRowGroupFrame::GetDirection()
    1652                 : {
    1653               0 :   nsTableFrame* table = nsTableFrame::GetTableFrame(this);
    1654                 :   return (NS_STYLE_DIRECTION_RTL ==
    1655               0 :           table->GetStyleVisibility()->mDirection);
    1656                 : }
    1657                 :   
    1658                 : NS_IMETHODIMP
    1659               0 : nsTableRowGroupFrame::GetLine(PRInt32    aLineNumber, 
    1660                 :                               nsIFrame** aFirstFrameOnLine, 
    1661                 :                               PRInt32*   aNumFramesOnLine,
    1662                 :                               nsRect&    aLineBounds, 
    1663                 :                               PRUint32*  aLineFlags)
    1664                 : {
    1665               0 :   NS_ENSURE_ARG_POINTER(aFirstFrameOnLine);
    1666               0 :   NS_ENSURE_ARG_POINTER(aNumFramesOnLine);
    1667               0 :   NS_ENSURE_ARG_POINTER(aLineFlags);
    1668                 : 
    1669               0 :   nsTableFrame* table = nsTableFrame::GetTableFrame(this);
    1670               0 :   nsTableCellMap* cellMap = table->GetCellMap();
    1671                 : 
    1672               0 :   *aLineFlags = 0;
    1673               0 :   *aFirstFrameOnLine = nsnull;
    1674               0 :   *aNumFramesOnLine = 0;
    1675               0 :   aLineBounds.SetRect(0, 0, 0, 0);
    1676                 :   
    1677               0 :   if ((aLineNumber < 0) || (aLineNumber >=  GetRowCount())) {
    1678               0 :     return NS_OK;
    1679                 :   }
    1680               0 :   aLineNumber += GetStartRowIndex(); 
    1681                 : 
    1682               0 :   *aNumFramesOnLine = cellMap->GetNumCellsOriginatingInRow(aLineNumber);
    1683               0 :   if (*aNumFramesOnLine == 0) {
    1684               0 :     return NS_OK;
    1685                 :   }
    1686               0 :   PRInt32 colCount = table->GetColCount();
    1687               0 :   for (PRInt32 i = 0; i < colCount; i++) {
    1688               0 :     CellData* data = cellMap->GetDataAt(aLineNumber, i);
    1689               0 :     if (data && data->IsOrig()) {
    1690               0 :       *aFirstFrameOnLine = (nsIFrame*)data->GetCellFrame();
    1691               0 :       nsIFrame* parent = (*aFirstFrameOnLine)->GetParent();
    1692               0 :       aLineBounds = parent->GetRect();
    1693               0 :       return NS_OK;
    1694                 :     }
    1695                 :   }
    1696               0 :   NS_ERROR("cellmap is lying");
    1697               0 :   return NS_ERROR_FAILURE;
    1698                 : }
    1699                 :   
    1700                 : PRInt32
    1701               0 : nsTableRowGroupFrame::FindLineContaining(nsIFrame* aFrame, PRInt32 aStartLine)
    1702                 : {
    1703               0 :   NS_ENSURE_ARG_POINTER(aFrame);
    1704                 :   
    1705               0 :   nsTableRowFrame *rowFrame = do_QueryFrame(aFrame);
    1706               0 :   NS_ASSERTION(rowFrame, "RowGroup contains a frame that is not a row");
    1707                 : 
    1708               0 :   PRInt32 rowIndexInGroup = rowFrame->GetRowIndex() - GetStartRowIndex();
    1709                 : 
    1710               0 :   return rowIndexInGroup >= aStartLine ? rowIndexInGroup : -1;
    1711                 : }
    1712                 : 
    1713                 : #ifdef IBMBIDI
    1714                 : NS_IMETHODIMP
    1715               0 : nsTableRowGroupFrame::CheckLineOrder(PRInt32                  aLine,
    1716                 :                                      bool                     *aIsReordered,
    1717                 :                                      nsIFrame                 **aFirstVisual,
    1718                 :                                      nsIFrame                 **aLastVisual)
    1719                 : {
    1720               0 :   *aIsReordered = false;
    1721               0 :   *aFirstVisual = nsnull;
    1722               0 :   *aLastVisual = nsnull;
    1723               0 :   return NS_OK;
    1724                 : }
    1725                 : #endif // IBMBIDI
    1726                 :   
    1727                 : NS_IMETHODIMP
    1728               0 : nsTableRowGroupFrame::FindFrameAt(PRInt32    aLineNumber, 
    1729                 :                                   nscoord    aX, 
    1730                 :                                   nsIFrame** aFrameFound,
    1731                 :                                   bool*    aXIsBeforeFirstFrame, 
    1732                 :                                   bool*    aXIsAfterLastFrame)
    1733                 : {
    1734               0 :    nsTableFrame* table = nsTableFrame::GetTableFrame(this);
    1735               0 :    nsTableCellMap* cellMap = table->GetCellMap();
    1736                 :    
    1737               0 :    *aFrameFound = nsnull;
    1738               0 :    *aXIsBeforeFirstFrame = true;
    1739               0 :    *aXIsAfterLastFrame = false;
    1740                 : 
    1741               0 :    aLineNumber += GetStartRowIndex();
    1742               0 :    PRInt32 numCells = cellMap->GetNumCellsOriginatingInRow(aLineNumber);
    1743               0 :    if (numCells == 0) {
    1744               0 :      return NS_OK;
    1745                 :    }
    1746                 :   
    1747               0 :    nsIFrame* frame = nsnull;
    1748               0 :    PRInt32 colCount = table->GetColCount();
    1749               0 :    for (PRInt32 i = 0; i < colCount; i++) {
    1750               0 :      CellData* data = cellMap->GetDataAt(aLineNumber, i);
    1751               0 :      if (data && data->IsOrig()) {
    1752               0 :        frame = (nsIFrame*)data->GetCellFrame();
    1753               0 :        break;
    1754                 :      }
    1755                 :    }
    1756               0 :    NS_ASSERTION(frame, "cellmap is lying");
    1757                 :    bool isRTL = (NS_STYLE_DIRECTION_RTL ==
    1758               0 :                    table->GetStyleVisibility()->mDirection);
    1759                 :    
    1760               0 :    nsIFrame* closestFromLeft = nsnull;
    1761               0 :    nsIFrame* closestFromRight = nsnull;
    1762               0 :    PRInt32 n = numCells;
    1763               0 :    nsIFrame* firstFrame = frame;
    1764               0 :    while (n--) {
    1765               0 :      nsRect rect = frame->GetRect();
    1766               0 :      if (rect.width > 0) {
    1767                 :        // If aX is inside this frame - this is it
    1768               0 :        if (rect.x <= aX && rect.XMost() > aX) {
    1769               0 :          closestFromLeft = closestFromRight = frame;
    1770                 :          break;
    1771                 :        }
    1772               0 :        if (rect.x < aX) {
    1773               0 :          if (!closestFromLeft ||
    1774               0 :              rect.XMost() > closestFromLeft->GetRect().XMost())
    1775               0 :            closestFromLeft = frame;
    1776                 :        }
    1777                 :        else {
    1778               0 :          if (!closestFromRight ||
    1779               0 :              rect.x < closestFromRight->GetRect().x)
    1780               0 :            closestFromRight = frame;
    1781                 :        }
    1782                 :      }
    1783               0 :      frame = frame->GetNextSibling();
    1784                 :    }
    1785               0 :    if (!closestFromLeft && !closestFromRight) {
    1786                 :      // All frames were zero-width. Just take the first one.
    1787               0 :      closestFromLeft = closestFromRight = firstFrame;
    1788                 :    }
    1789               0 :    *aXIsBeforeFirstFrame = isRTL ? !closestFromRight : !closestFromLeft;
    1790               0 :    *aXIsAfterLastFrame =   isRTL ? !closestFromLeft : !closestFromRight;
    1791               0 :    if (closestFromLeft == closestFromRight) {
    1792               0 :      *aFrameFound = closestFromLeft;
    1793                 :    }
    1794               0 :    else if (!closestFromLeft) {
    1795               0 :      *aFrameFound = closestFromRight;
    1796                 :    }
    1797               0 :    else if (!closestFromRight) {
    1798               0 :      *aFrameFound = closestFromLeft;
    1799                 :    }
    1800                 :    else { // we're between two frames
    1801               0 :      nscoord delta = closestFromRight->GetRect().x -
    1802               0 :                      closestFromLeft->GetRect().XMost();
    1803               0 :      if (aX < closestFromLeft->GetRect().XMost() + delta/2)
    1804               0 :        *aFrameFound = closestFromLeft;
    1805                 :      else
    1806               0 :        *aFrameFound = closestFromRight;
    1807                 :   }
    1808               0 :   return NS_OK;
    1809                 : }
    1810                 : 
    1811                 : NS_IMETHODIMP
    1812               0 : nsTableRowGroupFrame::GetNextSiblingOnLine(nsIFrame*& aFrame, 
    1813                 :                                            PRInt32    aLineNumber)
    1814                 : {
    1815               0 :   NS_ENSURE_ARG_POINTER(aFrame);
    1816               0 :   aFrame = aFrame->GetNextSibling();
    1817               0 :   return NS_OK;
    1818                 : }
    1819                 : 
    1820                 : //end nsLineIterator methods
    1821                 : 
    1822                 : static void
    1823               0 : DestroyFrameCursorData(void* aPropertyValue)
    1824                 : {
    1825               0 :   delete static_cast<nsTableRowGroupFrame::FrameCursorData*>(aPropertyValue);
    1826               0 : }
    1827                 : 
    1828               0 : NS_DECLARE_FRAME_PROPERTY(RowCursorProperty, DestroyFrameCursorData)
    1829                 : 
    1830                 : void
    1831               0 : nsTableRowGroupFrame::ClearRowCursor()
    1832                 : {
    1833               0 :   if (!(GetStateBits() & NS_ROWGROUP_HAS_ROW_CURSOR))
    1834               0 :     return;
    1835                 : 
    1836               0 :   RemoveStateBits(NS_ROWGROUP_HAS_ROW_CURSOR);
    1837               0 :   Properties().Delete(RowCursorProperty());
    1838                 : }
    1839                 : 
    1840                 : nsTableRowGroupFrame::FrameCursorData*
    1841               0 : nsTableRowGroupFrame::SetupRowCursor()
    1842                 : {
    1843               0 :   if (GetStateBits() & NS_ROWGROUP_HAS_ROW_CURSOR) {
    1844                 :     // We already have a valid row cursor. Don't waste time rebuilding it.
    1845               0 :     return nsnull;
    1846                 :   }
    1847                 : 
    1848               0 :   nsIFrame* f = mFrames.FirstChild();
    1849                 :   PRInt32 count;
    1850               0 :   for (count = 0; f && count < MIN_ROWS_NEEDING_CURSOR; ++count) {
    1851               0 :     f = f->GetNextSibling();
    1852                 :   }
    1853               0 :   if (!f) {
    1854                 :     // Less than MIN_ROWS_NEEDING_CURSOR rows, so just don't bother
    1855               0 :     return nsnull;
    1856                 :   }
    1857                 : 
    1858               0 :   FrameCursorData* data = new FrameCursorData();
    1859               0 :   if (!data)
    1860               0 :     return nsnull;
    1861               0 :   Properties().Set(RowCursorProperty(), data);
    1862               0 :   AddStateBits(NS_ROWGROUP_HAS_ROW_CURSOR);
    1863               0 :   return data;
    1864                 : }
    1865                 : 
    1866                 : nsIFrame*
    1867               0 : nsTableRowGroupFrame::GetFirstRowContaining(nscoord aY, nscoord* aOverflowAbove)
    1868                 : {
    1869               0 :   if (!(GetStateBits() & NS_ROWGROUP_HAS_ROW_CURSOR))
    1870               0 :     return nsnull;
    1871                 : 
    1872                 :   FrameCursorData* property = static_cast<FrameCursorData*>
    1873               0 :     (Properties().Get(RowCursorProperty()));
    1874               0 :   PRUint32 cursorIndex = property->mCursorIndex;
    1875               0 :   PRUint32 frameCount = property->mFrames.Length();
    1876               0 :   if (cursorIndex >= frameCount)
    1877               0 :     return nsnull;
    1878               0 :   nsIFrame* cursorFrame = property->mFrames[cursorIndex];
    1879                 : 
    1880                 :   // The cursor's frame list excludes frames with empty overflow-area, so
    1881                 :   // we don't need to check that here.
    1882                 :   
    1883                 :   // We use property->mOverflowBelow here instead of computing the frame's
    1884                 :   // true overflowArea.YMost(), because it is essential for the thresholds
    1885                 :   // to form a monotonically increasing sequence. Otherwise we would break
    1886                 :   // encountering a row whose overflowArea.YMost() is <= aY but which has
    1887                 :   // a row above it containing cell(s) that span to include aY.
    1888               0 :   while (cursorIndex > 0 &&
    1889               0 :          cursorFrame->GetRect().YMost() + property->mOverflowBelow > aY) {
    1890               0 :     --cursorIndex;
    1891               0 :     cursorFrame = property->mFrames[cursorIndex];
    1892                 :   }
    1893               0 :   while (cursorIndex + 1 < frameCount &&
    1894               0 :          cursorFrame->GetRect().YMost() + property->mOverflowBelow <= aY) {
    1895               0 :     ++cursorIndex;
    1896               0 :     cursorFrame = property->mFrames[cursorIndex];
    1897                 :   }
    1898                 : 
    1899               0 :   property->mCursorIndex = cursorIndex;
    1900               0 :   *aOverflowAbove = property->mOverflowAbove;
    1901               0 :   return cursorFrame;
    1902                 : }
    1903                 : 
    1904                 : bool
    1905               0 : nsTableRowGroupFrame::FrameCursorData::AppendFrame(nsIFrame* aFrame)
    1906                 : {
    1907               0 :   nsRect overflowRect = aFrame->GetVisualOverflowRect();
    1908               0 :   if (overflowRect.IsEmpty())
    1909               0 :     return true;
    1910               0 :   nscoord overflowAbove = -overflowRect.y;
    1911               0 :   nscoord overflowBelow = overflowRect.YMost() - aFrame->GetSize().height;
    1912               0 :   mOverflowAbove = NS_MAX(mOverflowAbove, overflowAbove);
    1913               0 :   mOverflowBelow = NS_MAX(mOverflowBelow, overflowBelow);
    1914               0 :   return mFrames.AppendElement(aFrame) != nsnull;
    1915                 : }

Generated by: LCOV version 1.7