LCOV - code coverage report
Current view: top level - layout/tables - nsTableRowGroupFrame.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 1002 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 66 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13