LCOV - app.info - layout/tables/nsTableRowGroupFrame.cpp

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-04-21 | 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