layout/tables/nsTableRowGroupFrame.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/tables/nsTableRowGroupFrame.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1931 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +#include "nsCOMPtr.h"
     1.9 +#include "nsTableRowGroupFrame.h"
    1.10 +#include "nsTableRowFrame.h"
    1.11 +#include "nsTableFrame.h"
    1.12 +#include "nsTableCellFrame.h"
    1.13 +#include "nsPresContext.h"
    1.14 +#include "nsStyleContext.h"
    1.15 +#include "nsStyleConsts.h"
    1.16 +#include "nsIContent.h"
    1.17 +#include "nsGkAtoms.h"
    1.18 +#include "nsIPresShell.h"
    1.19 +#include "nsCSSRendering.h"
    1.20 +#include "nsHTMLParts.h"
    1.21 +#include "nsCSSFrameConstructor.h"
    1.22 +#include "nsDisplayList.h"
    1.23 +
    1.24 +#include "nsCellMap.h"//table cell navigation
    1.25 +#include <algorithm>
    1.26 +
    1.27 +using namespace mozilla;
    1.28 +using namespace mozilla::layout;
    1.29 +
    1.30 +nsTableRowGroupFrame::nsTableRowGroupFrame(nsStyleContext* aContext):
    1.31 +  nsContainerFrame(aContext)
    1.32 +{
    1.33 +  SetRepeatable(false);
    1.34 +}
    1.35 +
    1.36 +nsTableRowGroupFrame::~nsTableRowGroupFrame()
    1.37 +{
    1.38 +}
    1.39 +
    1.40 +void
    1.41 +nsTableRowGroupFrame::DestroyFrom(nsIFrame* aDestructRoot)
    1.42 +{
    1.43 +  if (GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) {
    1.44 +    nsTableFrame::UnregisterPositionedTablePart(this, aDestructRoot);
    1.45 +  }
    1.46 +
    1.47 +  nsContainerFrame::DestroyFrom(aDestructRoot);
    1.48 +}
    1.49 +
    1.50 +NS_QUERYFRAME_HEAD(nsTableRowGroupFrame)
    1.51 +  NS_QUERYFRAME_ENTRY(nsTableRowGroupFrame)
    1.52 +NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
    1.53 +
    1.54 +int32_t
    1.55 +nsTableRowGroupFrame::GetRowCount()
    1.56 +{
    1.57 +#ifdef DEBUG
    1.58 +  for (nsFrameList::Enumerator e(mFrames); !e.AtEnd(); e.Next()) {
    1.59 +    NS_ASSERTION(e.get()->StyleDisplay()->mDisplay ==
    1.60 +                   NS_STYLE_DISPLAY_TABLE_ROW,
    1.61 +                 "Unexpected display");
    1.62 +    NS_ASSERTION(e.get()->GetType() == nsGkAtoms::tableRowFrame,
    1.63 +                 "Unexpected frame type");
    1.64 +  }
    1.65 +#endif
    1.66 +  
    1.67 +  return mFrames.GetLength();
    1.68 +}
    1.69 +
    1.70 +int32_t nsTableRowGroupFrame::GetStartRowIndex()
    1.71 +{
    1.72 +  int32_t result = -1;
    1.73 +  if (mFrames.NotEmpty()) {
    1.74 +    NS_ASSERTION(mFrames.FirstChild()->GetType() == nsGkAtoms::tableRowFrame,
    1.75 +                 "Unexpected frame type");
    1.76 +    result = static_cast<nsTableRowFrame*>(mFrames.FirstChild())->GetRowIndex();
    1.77 +  }
    1.78 +  // if the row group doesn't have any children, get it the hard way
    1.79 +  if (-1 == result) {
    1.80 +    nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
    1.81 +    return tableFrame->GetStartRowIndex(this);
    1.82 +  }
    1.83 +      
    1.84 +  return result;
    1.85 +}
    1.86 +
    1.87 +void  nsTableRowGroupFrame::AdjustRowIndices(int32_t aRowIndex,
    1.88 +                                             int32_t anAdjustment)
    1.89 +{
    1.90 +  nsIFrame* rowFrame = GetFirstPrincipalChild();
    1.91 +  for ( ; rowFrame; rowFrame = rowFrame->GetNextSibling()) {
    1.92 +    if (NS_STYLE_DISPLAY_TABLE_ROW==rowFrame->StyleDisplay()->mDisplay) {
    1.93 +      int32_t index = ((nsTableRowFrame*)rowFrame)->GetRowIndex();
    1.94 +      if (index >= aRowIndex)
    1.95 +        ((nsTableRowFrame *)rowFrame)->SetRowIndex(index+anAdjustment);
    1.96 +    }
    1.97 +  }
    1.98 +}
    1.99 +nsresult
   1.100 +nsTableRowGroupFrame::InitRepeatedFrame(nsPresContext*        aPresContext,
   1.101 +                                        nsTableRowGroupFrame* aHeaderFooterFrame)
   1.102 +{
   1.103 +  nsTableRowFrame* copyRowFrame = GetFirstRow();
   1.104 +  nsTableRowFrame* originalRowFrame = aHeaderFooterFrame->GetFirstRow();
   1.105 +  AddStateBits(NS_REPEATED_ROW_OR_ROWGROUP);
   1.106 +  while (copyRowFrame && originalRowFrame) {
   1.107 +    copyRowFrame->AddStateBits(NS_REPEATED_ROW_OR_ROWGROUP);
   1.108 +    int rowIndex = originalRowFrame->GetRowIndex();
   1.109 +    copyRowFrame->SetRowIndex(rowIndex);
   1.110 +
   1.111 +    // For each table cell frame set its column index
   1.112 +    nsTableCellFrame* originalCellFrame = originalRowFrame->GetFirstCell();
   1.113 +    nsTableCellFrame* copyCellFrame     = copyRowFrame->GetFirstCell();
   1.114 +    while (copyCellFrame && originalCellFrame) {
   1.115 +      NS_ASSERTION(originalCellFrame->GetContent() == copyCellFrame->GetContent(),
   1.116 +                   "cell frames have different content");
   1.117 +      int32_t colIndex;
   1.118 +      originalCellFrame->GetColIndex(colIndex);
   1.119 +      copyCellFrame->SetColIndex(colIndex);
   1.120 +        
   1.121 +      // Move to the next cell frame
   1.122 +      copyCellFrame     = copyCellFrame->GetNextCell();
   1.123 +      originalCellFrame = originalCellFrame->GetNextCell();
   1.124 +    }
   1.125 +    
   1.126 +    // Move to the next row frame
   1.127 +    originalRowFrame = originalRowFrame->GetNextRow();
   1.128 +    copyRowFrame = copyRowFrame->GetNextRow();
   1.129 +  }
   1.130 +
   1.131 +  return NS_OK;
   1.132 +}
   1.133 +
   1.134 +/**
   1.135 + * We need a custom display item for table row backgrounds. This is only used
   1.136 + * when the table row is the root of a stacking context (e.g., has 'opacity').
   1.137 + * Table row backgrounds can extend beyond the row frame bounds, when
   1.138 + * the row contains row-spanning cells.
   1.139 + */
   1.140 +class nsDisplayTableRowGroupBackground : public nsDisplayTableItem {
   1.141 +public:
   1.142 +  nsDisplayTableRowGroupBackground(nsDisplayListBuilder* aBuilder,
   1.143 +                                   nsTableRowGroupFrame* aFrame) :
   1.144 +    nsDisplayTableItem(aBuilder, aFrame) {
   1.145 +    MOZ_COUNT_CTOR(nsDisplayTableRowGroupBackground);
   1.146 +  }
   1.147 +#ifdef NS_BUILD_REFCNT_LOGGING
   1.148 +  virtual ~nsDisplayTableRowGroupBackground() {
   1.149 +    MOZ_COUNT_DTOR(nsDisplayTableRowGroupBackground);
   1.150 +  }
   1.151 +#endif
   1.152 +
   1.153 +  virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
   1.154 +                                         const nsDisplayItemGeometry* aGeometry,
   1.155 +                                         nsRegion *aInvalidRegion) MOZ_OVERRIDE;
   1.156 +  virtual void Paint(nsDisplayListBuilder* aBuilder,
   1.157 +                     nsRenderingContext* aCtx) MOZ_OVERRIDE;
   1.158 +
   1.159 +  NS_DISPLAY_DECL_NAME("TableRowGroupBackground", TYPE_TABLE_ROW_GROUP_BACKGROUND)
   1.160 +};
   1.161 +
   1.162 +void
   1.163 +nsDisplayTableRowGroupBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
   1.164 +                                                            const nsDisplayItemGeometry* aGeometry,
   1.165 +                                                            nsRegion *aInvalidRegion)
   1.166 +{
   1.167 +  if (aBuilder->ShouldSyncDecodeImages()) {
   1.168 +    if (nsTableFrame::AnyTablePartHasUndecodedBackgroundImage(mFrame, mFrame->GetNextSibling())) {
   1.169 +      bool snap;
   1.170 +      aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
   1.171 +    }
   1.172 +  }
   1.173 +
   1.174 +  nsDisplayTableItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
   1.175 +}
   1.176 +
   1.177 +void
   1.178 +nsDisplayTableRowGroupBackground::Paint(nsDisplayListBuilder* aBuilder,
   1.179 +                                        nsRenderingContext* aCtx)
   1.180 +{
   1.181 +  nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(mFrame);
   1.182 +  TableBackgroundPainter painter(tableFrame,
   1.183 +                                 TableBackgroundPainter::eOrigin_TableRowGroup,
   1.184 +                                 mFrame->PresContext(), *aCtx,
   1.185 +                                 mVisibleRect, ToReferenceFrame(),
   1.186 +                                 aBuilder->GetBackgroundPaintFlags());
   1.187 +  painter.PaintRowGroup(static_cast<nsTableRowGroupFrame*>(mFrame));
   1.188 +}
   1.189 +
   1.190 +// Handle the child-traversal part of DisplayGenericTablePart
   1.191 +static void
   1.192 +DisplayRows(nsDisplayListBuilder* aBuilder, nsFrame* aFrame,
   1.193 +            const nsRect& aDirtyRect, const nsDisplayListSet& aLists)
   1.194 +{
   1.195 +  nscoord overflowAbove;
   1.196 +  nsTableRowGroupFrame* f = static_cast<nsTableRowGroupFrame*>(aFrame);
   1.197 +  // Don't try to use the row cursor if we have to descend into placeholders;
   1.198 +  // we might have rows containing placeholders, where the row's overflow
   1.199 +  // area doesn't intersect the dirty rect but we need to descend into the row
   1.200 +  // to see out of flows.
   1.201 +  // Note that we really want to check ShouldDescendIntoFrame for all
   1.202 +  // the rows in |f|, but that's exactly what we're trying to avoid, so we
   1.203 +  // approximate it by checking it for |f|: if it's true for any row
   1.204 +  // in |f| then it's true for |f| itself.
   1.205 +  nsIFrame* kid = aBuilder->ShouldDescendIntoFrame(f) ?
   1.206 +    nullptr : f->GetFirstRowContaining(aDirtyRect.y, &overflowAbove);
   1.207 +  
   1.208 +  if (kid) {
   1.209 +    // have a cursor, use it
   1.210 +    while (kid) {
   1.211 +      if (kid->GetRect().y - overflowAbove >= aDirtyRect.YMost())
   1.212 +        break;
   1.213 +      f->BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
   1.214 +      kid = kid->GetNextSibling();
   1.215 +    }
   1.216 +    return;
   1.217 +  }
   1.218 +  
   1.219 +  // No cursor. Traverse children the hard way and build a cursor while we're at it
   1.220 +  nsTableRowGroupFrame::FrameCursorData* cursor = f->SetupRowCursor();
   1.221 +  kid = f->GetFirstPrincipalChild();
   1.222 +  while (kid) {
   1.223 +    f->BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
   1.224 +    
   1.225 +    if (cursor) {
   1.226 +      if (!cursor->AppendFrame(kid)) {
   1.227 +        f->ClearRowCursor();
   1.228 +        return;
   1.229 +      }
   1.230 +    }
   1.231 +  
   1.232 +    kid = kid->GetNextSibling();
   1.233 +  }
   1.234 +  if (cursor) {
   1.235 +    cursor->FinishBuildingCursor();
   1.236 +  }
   1.237 +}
   1.238 +
   1.239 +void
   1.240 +nsTableRowGroupFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
   1.241 +                                       const nsRect&           aDirtyRect,
   1.242 +                                       const nsDisplayListSet& aLists)
   1.243 +{
   1.244 +  nsDisplayTableItem* item = nullptr;
   1.245 +  if (IsVisibleInSelection(aBuilder)) {
   1.246 +    bool isRoot = aBuilder->IsAtRootOfPseudoStackingContext();
   1.247 +    if (isRoot) {
   1.248 +      // This background is created regardless of whether this frame is
   1.249 +      // visible or not. Visibility decisions are delegated to the
   1.250 +      // table background painter.
   1.251 +      item = new (aBuilder) nsDisplayTableRowGroupBackground(aBuilder, this);
   1.252 +      aLists.BorderBackground()->AppendNewToTop(item);
   1.253 +    }
   1.254 +  }  
   1.255 +  nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect,
   1.256 +                                        aLists, item, DisplayRows);
   1.257 +}
   1.258 +
   1.259 +int
   1.260 +nsTableRowGroupFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const
   1.261 +{
   1.262 +  int skip = 0;
   1.263 +  if (nullptr != GetPrevInFlow()) {
   1.264 +    skip |= LOGICAL_SIDE_B_START;
   1.265 +  }
   1.266 +  if (nullptr != GetNextInFlow()) {
   1.267 +    skip |= LOGICAL_SIDE_B_END;
   1.268 +  }
   1.269 +  return skip;
   1.270 +}
   1.271 +
   1.272 +// Position and size aKidFrame and update our reflow state. The origin of
   1.273 +// aKidRect is relative to the upper-left origin of our frame
   1.274 +void 
   1.275 +nsTableRowGroupFrame::PlaceChild(nsPresContext*         aPresContext,
   1.276 +                                 nsRowGroupReflowState& aReflowState,
   1.277 +                                 nsIFrame*              aKidFrame,
   1.278 +                                 nsHTMLReflowMetrics&   aDesiredSize,
   1.279 +                                 const nsRect&          aOriginalKidRect,
   1.280 +                                 const nsRect&          aOriginalKidVisualOverflow)
   1.281 +{
   1.282 +  bool isFirstReflow =
   1.283 +    (aKidFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
   1.284 +
   1.285 +  // Place and size the child
   1.286 +  FinishReflowChild(aKidFrame, aPresContext, aDesiredSize, nullptr, 0,
   1.287 +                    aReflowState.y, 0);
   1.288 +
   1.289 +  nsTableFrame::InvalidateTableFrame(aKidFrame, aOriginalKidRect,
   1.290 +                                     aOriginalKidVisualOverflow, isFirstReflow);
   1.291 +
   1.292 +  // Adjust the running y-offset
   1.293 +  aReflowState.y += aDesiredSize.Height();
   1.294 +
   1.295 +  // If our height is constrained then update the available height
   1.296 +  if (NS_UNCONSTRAINEDSIZE != aReflowState.availSize.height) {
   1.297 +    aReflowState.availSize.height -= aDesiredSize.Height();
   1.298 +  }
   1.299 +}
   1.300 +
   1.301 +void
   1.302 +nsTableRowGroupFrame::InitChildReflowState(nsPresContext&     aPresContext, 
   1.303 +                                           bool               aBorderCollapse,
   1.304 +                                           nsHTMLReflowState& aReflowState)                                    
   1.305 +{
   1.306 +  nsMargin collapseBorder;
   1.307 +  nsMargin padding(0,0,0,0);
   1.308 +  nsMargin* pCollapseBorder = nullptr;
   1.309 +  if (aBorderCollapse) {
   1.310 +    nsTableRowFrame *rowFrame = do_QueryFrame(aReflowState.frame);
   1.311 +    if (rowFrame) {
   1.312 +      pCollapseBorder = rowFrame->GetBCBorderWidth(collapseBorder);
   1.313 +    }
   1.314 +  }
   1.315 +  aReflowState.Init(&aPresContext, -1, -1, pCollapseBorder, &padding);
   1.316 +}
   1.317 +
   1.318 +static void
   1.319 +CacheRowHeightsForPrinting(nsPresContext*   aPresContext,
   1.320 +                           nsTableRowFrame* aFirstRow)
   1.321 +{
   1.322 +  for (nsTableRowFrame* row = aFirstRow; row; row = row->GetNextRow()) {
   1.323 +    if (!row->GetPrevInFlow()) {
   1.324 +      row->SetHasUnpaginatedHeight(true);
   1.325 +      row->SetUnpaginatedHeight(aPresContext, row->GetSize().height);
   1.326 +    }
   1.327 +  }
   1.328 +}
   1.329 +
   1.330 +nsresult
   1.331 +nsTableRowGroupFrame::ReflowChildren(nsPresContext*         aPresContext,
   1.332 +                                     nsHTMLReflowMetrics&   aDesiredSize,
   1.333 +                                     nsRowGroupReflowState& aReflowState,
   1.334 +                                     nsReflowStatus&        aStatus,
   1.335 +                                     bool*                aPageBreakBeforeEnd)
   1.336 +{
   1.337 +  if (aPageBreakBeforeEnd) 
   1.338 +    *aPageBreakBeforeEnd = false;
   1.339 +
   1.340 +  nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
   1.341 +  nsresult rv = NS_OK;
   1.342 +  const bool borderCollapse = tableFrame->IsBorderCollapse();
   1.343 +  nscoord cellSpacingY = tableFrame->GetCellSpacingY();
   1.344 +
   1.345 +  // XXXldb Should we really be checking this rather than available height?
   1.346 +  // (Think about multi-column layout!)
   1.347 +  bool isPaginated = aPresContext->IsPaginated() && 
   1.348 +                       NS_UNCONSTRAINEDSIZE != aReflowState.availSize.height;
   1.349 +
   1.350 +  bool haveRow = false;
   1.351 +  bool reflowAllKids = aReflowState.reflowState.ShouldReflowAllKids() ||
   1.352 +                         tableFrame->IsGeometryDirty();
   1.353 +  bool needToCalcRowHeights = reflowAllKids;
   1.354 +
   1.355 +  nsIFrame *prevKidFrame = nullptr;
   1.356 +  for (nsIFrame* kidFrame = mFrames.FirstChild(); kidFrame;
   1.357 +       prevKidFrame = kidFrame, kidFrame = kidFrame->GetNextSibling()) {
   1.358 +    nsTableRowFrame *rowFrame = do_QueryFrame(kidFrame);
   1.359 +    if (!rowFrame) {
   1.360 +      // XXXldb nsCSSFrameConstructor needs to enforce this!
   1.361 +      NS_NOTREACHED("yikes, a non-row child");
   1.362 +      continue;
   1.363 +    }
   1.364 +
   1.365 +    haveRow = true;
   1.366 +
   1.367 +    // Reflow the row frame
   1.368 +    if (reflowAllKids ||
   1.369 +        NS_SUBTREE_DIRTY(kidFrame) ||
   1.370 +        (aReflowState.reflowState.mFlags.mSpecialHeightReflow &&
   1.371 +         (isPaginated || (kidFrame->GetStateBits() &
   1.372 +                          NS_FRAME_CONTAINS_RELATIVE_HEIGHT)))) {
   1.373 +      nsRect oldKidRect = kidFrame->GetRect();
   1.374 +      nsRect oldKidVisualOverflow = kidFrame->GetVisualOverflowRect();
   1.375 +
   1.376 +      // XXXldb We used to only pass aDesiredSize.mFlags through for the
   1.377 +      // incremental reflow codepath.
   1.378 +      nsHTMLReflowMetrics desiredSize(aReflowState.reflowState,
   1.379 +                                      aDesiredSize.mFlags);
   1.380 +      desiredSize.Width() = desiredSize.Height() = 0;
   1.381 +  
   1.382 +      // Reflow the child into the available space, giving it as much height as
   1.383 +      // it wants. We'll deal with splitting later after we've computed the row
   1.384 +      // heights, taking into account cells with row spans...
   1.385 +      nsSize kidAvailSize(aReflowState.availSize.width, NS_UNCONSTRAINEDSIZE);
   1.386 +      nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState,
   1.387 +                                       kidFrame, kidAvailSize,
   1.388 +                                       -1, -1,
   1.389 +                                       nsHTMLReflowState::CALLER_WILL_INIT);
   1.390 +      InitChildReflowState(*aPresContext, borderCollapse, kidReflowState);
   1.391 +
   1.392 +      // This can indicate that columns were resized.
   1.393 +      if (aReflowState.reflowState.mFlags.mHResize)
   1.394 +        kidReflowState.mFlags.mHResize = true;
   1.395 +     
   1.396 +      NS_ASSERTION(kidFrame == mFrames.FirstChild() || prevKidFrame, 
   1.397 +                   "If we're not on the first frame, we should have a "
   1.398 +                   "previous sibling...");
   1.399 +      // If prev row has nonzero YMost, then we can't be at the top of the page
   1.400 +      if (prevKidFrame && prevKidFrame->GetRect().YMost() > 0) {
   1.401 +        kidReflowState.mFlags.mIsTopOfPage = false;
   1.402 +      }
   1.403 +
   1.404 +      rv = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState,
   1.405 +                       0, aReflowState.y, 0, aStatus);
   1.406 +
   1.407 +      // Place the child
   1.408 +      PlaceChild(aPresContext, aReflowState, kidFrame, desiredSize,
   1.409 +                 oldKidRect, oldKidVisualOverflow);
   1.410 +      aReflowState.y += cellSpacingY;
   1.411 +
   1.412 +      if (!reflowAllKids) {
   1.413 +        if (IsSimpleRowFrame(aReflowState.tableFrame, kidFrame)) {
   1.414 +          // Inform the row of its new height.
   1.415 +          rowFrame->DidResize();
   1.416 +          // the overflow area may have changed inflate the overflow area
   1.417 +          const nsStylePosition *stylePos = StylePosition();
   1.418 +          nsStyleUnit unit = stylePos->mHeight.GetUnit();
   1.419 +          if (aReflowState.tableFrame->IsAutoHeight() &&
   1.420 +              unit != eStyleUnit_Coord) {
   1.421 +            // Because other cells in the row may need to be aligned
   1.422 +            // differently, repaint the entire row
   1.423 +            nsRect kidRect(0, aReflowState.y,
   1.424 +                           desiredSize.Width(), desiredSize.Height());
   1.425 +            InvalidateFrame();
   1.426 +          }
   1.427 +          else if (oldKidRect.height != desiredSize.Height())
   1.428 +            needToCalcRowHeights = true;
   1.429 +        } else {
   1.430 +          needToCalcRowHeights = true;
   1.431 +        }
   1.432 +      }
   1.433 +
   1.434 +      if (isPaginated && aPageBreakBeforeEnd && !*aPageBreakBeforeEnd) {
   1.435 +        nsTableRowFrame* nextRow = rowFrame->GetNextRow();
   1.436 +        if (nextRow) {
   1.437 +          *aPageBreakBeforeEnd = nsTableFrame::PageBreakAfter(kidFrame, nextRow);
   1.438 +        }
   1.439 +      }
   1.440 +    } else {
   1.441 +      SlideChild(aReflowState, kidFrame);
   1.442 +
   1.443 +      // Adjust the running y-offset so we know where the next row should be placed
   1.444 +      nscoord height = kidFrame->GetSize().height + cellSpacingY;
   1.445 +      aReflowState.y += height;
   1.446 +
   1.447 +      if (NS_UNCONSTRAINEDSIZE != aReflowState.availSize.height) {
   1.448 +        aReflowState.availSize.height -= height;
   1.449 +      }
   1.450 +    }
   1.451 +    ConsiderChildOverflow(aDesiredSize.mOverflowAreas, kidFrame);
   1.452 +  }
   1.453 +
   1.454 +  if (haveRow)
   1.455 +    aReflowState.y -= cellSpacingY;
   1.456 +
   1.457 +  // Return our desired rect
   1.458 +  aDesiredSize.Width() = aReflowState.reflowState.AvailableWidth();
   1.459 +  aDesiredSize.Height() = aReflowState.y;
   1.460 +
   1.461 +  if (aReflowState.reflowState.mFlags.mSpecialHeightReflow) {
   1.462 +    DidResizeRows(aDesiredSize);
   1.463 +    if (isPaginated) {
   1.464 +      CacheRowHeightsForPrinting(aPresContext, GetFirstRow());
   1.465 +    }
   1.466 +  }
   1.467 +  else if (needToCalcRowHeights) {
   1.468 +    CalculateRowHeights(aPresContext, aDesiredSize, aReflowState.reflowState);
   1.469 +    if (!reflowAllKids) {
   1.470 +      InvalidateFrame();
   1.471 +    }
   1.472 +  }
   1.473 +
   1.474 +  return rv;
   1.475 +}
   1.476 +
   1.477 +nsTableRowFrame*  
   1.478 +nsTableRowGroupFrame::GetFirstRow() 
   1.479 +{
   1.480 +  for (nsIFrame* childFrame = mFrames.FirstChild(); childFrame;
   1.481 +       childFrame = childFrame->GetNextSibling()) {
   1.482 +    nsTableRowFrame *rowFrame = do_QueryFrame(childFrame);
   1.483 +    if (rowFrame) {
   1.484 +      return rowFrame;
   1.485 +    }
   1.486 +  }
   1.487 +  return nullptr;
   1.488 +}
   1.489 +
   1.490 +
   1.491 +struct RowInfo {
   1.492 +  RowInfo() { height = pctHeight = hasStyleHeight = hasPctHeight = isSpecial = 0; }
   1.493 +  unsigned height;       // content height or fixed height, excluding pct height
   1.494 +  unsigned pctHeight:29; // pct height
   1.495 +  unsigned hasStyleHeight:1; 
   1.496 +  unsigned hasPctHeight:1; 
   1.497 +  unsigned isSpecial:1; // there is no cell originating in the row with rowspan=1 and there are at
   1.498 +                        // least 2 cells spanning the row and there is no style height on the row
   1.499 +};
   1.500 +
   1.501 +static void
   1.502 +UpdateHeights(RowInfo& aRowInfo,
   1.503 +              nscoord  aAdditionalHeight,
   1.504 +              nscoord& aTotal,
   1.505 +              nscoord& aUnconstrainedTotal)
   1.506 +{
   1.507 +  aRowInfo.height += aAdditionalHeight;
   1.508 +  aTotal          += aAdditionalHeight;
   1.509 +  if (!aRowInfo.hasStyleHeight) {
   1.510 +    aUnconstrainedTotal += aAdditionalHeight;
   1.511 +  }
   1.512 +}
   1.513 +
   1.514 +void 
   1.515 +nsTableRowGroupFrame::DidResizeRows(nsHTMLReflowMetrics& aDesiredSize)
   1.516 +{
   1.517 +  // update the cells spanning rows with their new heights
   1.518 +  // this is the place where all of the cells in the row get set to the height of the row
   1.519 +  // Reset the overflow area
   1.520 +  aDesiredSize.mOverflowAreas.Clear();
   1.521 +  for (nsTableRowFrame* rowFrame = GetFirstRow();
   1.522 +       rowFrame; rowFrame = rowFrame->GetNextRow()) {
   1.523 +    rowFrame->DidResize();
   1.524 +    ConsiderChildOverflow(aDesiredSize.mOverflowAreas, rowFrame);
   1.525 +  }
   1.526 +}
   1.527 +
   1.528 +// This calculates the height of all the rows and takes into account 
   1.529 +// style height on the row group, style heights on rows and cells, style heights on rowspans. 
   1.530 +// Actual row heights will be adjusted later if the table has a style height.
   1.531 +// Even if rows don't change height, this method must be called to set the heights of each
   1.532 +// cell in the row to the height of its row.
   1.533 +void 
   1.534 +nsTableRowGroupFrame::CalculateRowHeights(nsPresContext*           aPresContext, 
   1.535 +                                          nsHTMLReflowMetrics&     aDesiredSize,
   1.536 +                                          const nsHTMLReflowState& aReflowState)
   1.537 +{
   1.538 +  nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
   1.539 +  const bool isPaginated = aPresContext->IsPaginated();
   1.540 +
   1.541 +  // all table cells have the same top and bottom margins, namely cellSpacingY
   1.542 +  nscoord cellSpacingY = tableFrame->GetCellSpacingY();
   1.543 +
   1.544 +  int32_t numEffCols = tableFrame->GetEffectiveColCount();
   1.545 +
   1.546 +  int32_t startRowIndex = GetStartRowIndex();
   1.547 +  // find the row corresponding to the row index we just found
   1.548 +  nsTableRowFrame* startRowFrame = GetFirstRow();
   1.549 +
   1.550 +  if (!startRowFrame) return;
   1.551 +
   1.552 +  // the current row group height is the y origin of the 1st row we are about to calculated a height for
   1.553 +  nscoord startRowGroupHeight = startRowFrame->GetPosition().y;
   1.554 +
   1.555 +  int32_t numRows = GetRowCount() - (startRowFrame->GetRowIndex() - GetStartRowIndex());
   1.556 +  // collect the current height of each row.  nscoord* rowHeights = nullptr;
   1.557 +  if (numRows <= 0)
   1.558 +    return;
   1.559 +
   1.560 +  nsTArray<RowInfo> rowInfo;
   1.561 +  if (!rowInfo.AppendElements(numRows)) {
   1.562 +    return;
   1.563 +  }
   1.564 +
   1.565 +  bool    hasRowSpanningCell = false;
   1.566 +  nscoord heightOfRows = 0;
   1.567 +  nscoord heightOfUnStyledRows = 0;
   1.568 +  // Get the height of each row without considering rowspans. This will be the max of 
   1.569 +  // the largest desired height of each cell, the largest style height of each cell, 
   1.570 +  // the style height of the row.
   1.571 +  nscoord pctHeightBasis = GetHeightBasis(aReflowState);
   1.572 +  int32_t rowIndex; // the index in rowInfo, not among the rows in the row group
   1.573 +  nsTableRowFrame* rowFrame;
   1.574 +  for (rowFrame = startRowFrame, rowIndex = 0; rowFrame; rowFrame = rowFrame->GetNextRow(), rowIndex++) {
   1.575 +    nscoord nonPctHeight = rowFrame->GetContentHeight();
   1.576 +    if (isPaginated) {
   1.577 +      nonPctHeight = std::max(nonPctHeight, rowFrame->GetSize().height);
   1.578 +    }
   1.579 +    if (!rowFrame->GetPrevInFlow()) {
   1.580 +      if (rowFrame->HasPctHeight()) {
   1.581 +        rowInfo[rowIndex].hasPctHeight = true;
   1.582 +        rowInfo[rowIndex].pctHeight = rowFrame->GetHeight(pctHeightBasis);
   1.583 +      }
   1.584 +      rowInfo[rowIndex].hasStyleHeight = rowFrame->HasStyleHeight();
   1.585 +      nonPctHeight = std::max(nonPctHeight, rowFrame->GetFixedHeight());
   1.586 +    }
   1.587 +    UpdateHeights(rowInfo[rowIndex], nonPctHeight, heightOfRows, heightOfUnStyledRows);
   1.588 +
   1.589 +    if (!rowInfo[rowIndex].hasStyleHeight) {
   1.590 +      if (isPaginated || tableFrame->HasMoreThanOneCell(rowIndex + startRowIndex)) {
   1.591 +        rowInfo[rowIndex].isSpecial = true;
   1.592 +        // iteratate the row's cell frames to see if any do not have rowspan > 1
   1.593 +        nsTableCellFrame* cellFrame = rowFrame->GetFirstCell();
   1.594 +        while (cellFrame) {
   1.595 +          int32_t rowSpan = tableFrame->GetEffectiveRowSpan(rowIndex + startRowIndex, *cellFrame);
   1.596 +          if (1 == rowSpan) { 
   1.597 +            rowInfo[rowIndex].isSpecial = false;
   1.598 +            break;
   1.599 +          }
   1.600 +          cellFrame = cellFrame->GetNextCell(); 
   1.601 +        }
   1.602 +      }
   1.603 +    }
   1.604 +    // See if a cell spans into the row. If so we'll have to do the next step
   1.605 +    if (!hasRowSpanningCell) {
   1.606 +      if (tableFrame->RowIsSpannedInto(rowIndex + startRowIndex, numEffCols)) {
   1.607 +        hasRowSpanningCell = true;
   1.608 +      }
   1.609 +    }
   1.610 +  }
   1.611 +
   1.612 +  if (hasRowSpanningCell) {
   1.613 +    // Get the height of cells with rowspans and allocate any extra space to the rows they span 
   1.614 +    // iteratate the child frames and process the row frames among them
   1.615 +    for (rowFrame = startRowFrame, rowIndex = 0; rowFrame; rowFrame = rowFrame->GetNextRow(), rowIndex++) {
   1.616 +      // See if the row has an originating cell with rowspan > 1. We cannot determine this for a row in a 
   1.617 +      // continued row group by calling RowHasSpanningCells, because the row's fif may not have any originating
   1.618 +      // cells yet the row may have a continued cell which originates in it.
   1.619 +      if (GetPrevInFlow() || tableFrame->RowHasSpanningCells(startRowIndex + rowIndex, numEffCols)) {
   1.620 +        nsTableCellFrame* cellFrame = rowFrame->GetFirstCell();
   1.621 +        // iteratate the row's cell frames 
   1.622 +        while (cellFrame) {
   1.623 +          int32_t rowSpan = tableFrame->GetEffectiveRowSpan(rowIndex + startRowIndex, *cellFrame);
   1.624 +          if ((rowIndex + rowSpan) > numRows) {
   1.625 +            // there might be rows pushed already to the nextInFlow
   1.626 +            rowSpan = numRows - rowIndex;
   1.627 +          }
   1.628 +          if (rowSpan > 1) { // a cell with rowspan > 1, determine the height of the rows it spans
   1.629 +            nscoord heightOfRowsSpanned = 0;
   1.630 +            nscoord heightOfUnStyledRowsSpanned = 0;
   1.631 +            nscoord numSpecialRowsSpanned = 0; 
   1.632 +            nscoord cellSpacingTotal = 0;
   1.633 +            int32_t spanX;
   1.634 +            for (spanX = 0; spanX < rowSpan; spanX++) {
   1.635 +              heightOfRowsSpanned += rowInfo[rowIndex + spanX].height;
   1.636 +              if (!rowInfo[rowIndex + spanX].hasStyleHeight) {
   1.637 +                heightOfUnStyledRowsSpanned += rowInfo[rowIndex + spanX].height;
   1.638 +              }
   1.639 +              if (0 != spanX) {
   1.640 +                cellSpacingTotal += cellSpacingY;
   1.641 +              }
   1.642 +              if (rowInfo[rowIndex + spanX].isSpecial) {
   1.643 +                numSpecialRowsSpanned++;
   1.644 +              }
   1.645 +            } 
   1.646 +            nscoord heightOfAreaSpanned = heightOfRowsSpanned + cellSpacingTotal;
   1.647 +            // get the height of the cell 
   1.648 +            nsSize cellFrameSize = cellFrame->GetSize();
   1.649 +            nsSize cellDesSize = cellFrame->GetDesiredSize();
   1.650 +            rowFrame->CalculateCellActualHeight(cellFrame, cellDesSize.height);
   1.651 +            cellFrameSize.height = cellDesSize.height;
   1.652 +            if (cellFrame->HasVerticalAlignBaseline()) {
   1.653 +              // to ensure that a spanning cell with a long descender doesn't
   1.654 +              // collide with the next row, we need to take into account the shift
   1.655 +              // that will be done to align the cell on the baseline of the row.
   1.656 +              cellFrameSize.height += rowFrame->GetMaxCellAscent() -
   1.657 +                                      cellFrame->GetCellBaseline();
   1.658 +            }
   1.659 +  
   1.660 +            if (heightOfAreaSpanned < cellFrameSize.height) {
   1.661 +              // the cell's height is larger than the available space of the rows it
   1.662 +              // spans so distribute the excess height to the rows affected
   1.663 +              nscoord extra     = cellFrameSize.height - heightOfAreaSpanned;
   1.664 +              nscoord extraUsed = 0;
   1.665 +              if (0 == numSpecialRowsSpanned) {
   1.666 +                //NS_ASSERTION(heightOfRowsSpanned > 0, "invalid row span situation");
   1.667 +                bool haveUnStyledRowsSpanned = (heightOfUnStyledRowsSpanned > 0);
   1.668 +                nscoord divisor = (haveUnStyledRowsSpanned) 
   1.669 +                                  ? heightOfUnStyledRowsSpanned : heightOfRowsSpanned;
   1.670 +                if (divisor > 0) {
   1.671 +                  for (spanX = rowSpan - 1; spanX >= 0; spanX--) {
   1.672 +                    if (!haveUnStyledRowsSpanned || !rowInfo[rowIndex + spanX].hasStyleHeight) {
   1.673 +                      // The amount of additional space each row gets is proportional to its height
   1.674 +                      float percent = ((float)rowInfo[rowIndex + spanX].height) / ((float)divisor);
   1.675 +                    
   1.676 +                      // give rows their percentage, except for the first row which gets the remainder
   1.677 +                      nscoord extraForRow = (0 == spanX) ? extra - extraUsed  
   1.678 +                                                         : NSToCoordRound(((float)(extra)) * percent);
   1.679 +                      extraForRow = std::min(extraForRow, extra - extraUsed);
   1.680 +                      // update the row height
   1.681 +                      UpdateHeights(rowInfo[rowIndex + spanX], extraForRow, heightOfRows, heightOfUnStyledRows);
   1.682 +                      extraUsed += extraForRow;
   1.683 +                      if (extraUsed >= extra) {
   1.684 +                        NS_ASSERTION((extraUsed == extra), "invalid row height calculation");
   1.685 +                        break;
   1.686 +                      }
   1.687 +                    }
   1.688 +                  }
   1.689 +                }
   1.690 +                else {
   1.691 +                  // put everything in the last row
   1.692 +                  UpdateHeights(rowInfo[rowIndex + rowSpan - 1], extra, heightOfRows, heightOfUnStyledRows);
   1.693 +                }
   1.694 +              }
   1.695 +              else {
   1.696 +                // give the extra to the special rows
   1.697 +                nscoord numSpecialRowsAllocated = 0;
   1.698 +                for (spanX = rowSpan - 1; spanX >= 0; spanX--) {
   1.699 +                  if (rowInfo[rowIndex + spanX].isSpecial) {
   1.700 +                    // The amount of additional space each degenerate row gets is proportional to the number of them
   1.701 +                    float percent = 1.0f / ((float)numSpecialRowsSpanned);
   1.702 +                    
   1.703 +                    // give rows their percentage, except for the first row which gets the remainder
   1.704 +                    nscoord extraForRow = (numSpecialRowsSpanned - 1 == numSpecialRowsAllocated) 
   1.705 +                                          ? extra - extraUsed  
   1.706 +                                          : NSToCoordRound(((float)(extra)) * percent);
   1.707 +                    extraForRow = std::min(extraForRow, extra - extraUsed);
   1.708 +                    // update the row height
   1.709 +                    UpdateHeights(rowInfo[rowIndex + spanX], extraForRow, heightOfRows, heightOfUnStyledRows);
   1.710 +                    extraUsed += extraForRow;
   1.711 +                    if (extraUsed >= extra) {
   1.712 +                      NS_ASSERTION((extraUsed == extra), "invalid row height calculation");
   1.713 +                      break;
   1.714 +                    }
   1.715 +                  }
   1.716 +                }
   1.717 +              }
   1.718 +            } 
   1.719 +          } // if (rowSpan > 1)
   1.720 +          cellFrame = cellFrame->GetNextCell(); 
   1.721 +        } // while (cellFrame)
   1.722 +      } // if (tableFrame->RowHasSpanningCells(startRowIndex + rowIndex) {
   1.723 +    } // while (rowFrame)
   1.724 +  }
   1.725 +
   1.726 +  // pct height rows have already got their content heights. Give them their pct heights up to pctHeightBasis
   1.727 +  nscoord extra = pctHeightBasis - heightOfRows;
   1.728 +  for (rowFrame = startRowFrame, rowIndex = 0; rowFrame && (extra > 0); rowFrame = rowFrame->GetNextRow(), rowIndex++) {
   1.729 +    RowInfo& rInfo = rowInfo[rowIndex];
   1.730 +    if (rInfo.hasPctHeight) {
   1.731 +      nscoord rowExtra = (rInfo.pctHeight > rInfo.height)  
   1.732 +                         ? rInfo.pctHeight - rInfo.height: 0;
   1.733 +      rowExtra = std::min(rowExtra, extra);
   1.734 +      UpdateHeights(rInfo, rowExtra, heightOfRows, heightOfUnStyledRows);
   1.735 +      extra -= rowExtra;
   1.736 +    }
   1.737 +  }
   1.738 +
   1.739 +  bool styleHeightAllocation = false;
   1.740 +  nscoord rowGroupHeight = startRowGroupHeight + heightOfRows + ((numRows - 1) * cellSpacingY);
   1.741 +  // if we have a style height, allocate the extra height to unconstrained rows
   1.742 +  if ((aReflowState.ComputedHeight() > rowGroupHeight) && 
   1.743 +      (NS_UNCONSTRAINEDSIZE != aReflowState.ComputedHeight())) {
   1.744 +    nscoord extraComputedHeight = aReflowState.ComputedHeight() - rowGroupHeight;
   1.745 +    nscoord extraUsed = 0;
   1.746 +    bool haveUnStyledRows = (heightOfUnStyledRows > 0);
   1.747 +    nscoord divisor = (haveUnStyledRows) 
   1.748 +                      ? heightOfUnStyledRows : heightOfRows;
   1.749 +    if (divisor > 0) {
   1.750 +      styleHeightAllocation = true;
   1.751 +      for (rowIndex = 0; rowIndex < numRows; rowIndex++) {
   1.752 +        if (!haveUnStyledRows || !rowInfo[rowIndex].hasStyleHeight) {
   1.753 +          // The amount of additional space each row gets is based on the
   1.754 +          // percentage of space it occupies
   1.755 +          float percent = ((float)rowInfo[rowIndex].height) / ((float)divisor);
   1.756 +          // give rows their percentage, except for the last row which gets the remainder
   1.757 +          nscoord extraForRow = (numRows - 1 == rowIndex) 
   1.758 +                                ? extraComputedHeight - extraUsed  
   1.759 +                                : NSToCoordRound(((float)extraComputedHeight) * percent);
   1.760 +          extraForRow = std::min(extraForRow, extraComputedHeight - extraUsed);
   1.761 +          // update the row height
   1.762 +          UpdateHeights(rowInfo[rowIndex], extraForRow, heightOfRows, heightOfUnStyledRows);
   1.763 +          extraUsed += extraForRow;
   1.764 +          if (extraUsed >= extraComputedHeight) {
   1.765 +            NS_ASSERTION((extraUsed == extraComputedHeight), "invalid row height calculation");
   1.766 +            break;
   1.767 +          }
   1.768 +        }
   1.769 +      }
   1.770 +    }
   1.771 +    rowGroupHeight = aReflowState.ComputedHeight();
   1.772 +  }
   1.773 +
   1.774 +  nscoord yOrigin = startRowGroupHeight;
   1.775 +  // update the rows with their (potentially) new heights
   1.776 +  for (rowFrame = startRowFrame, rowIndex = 0; rowFrame; rowFrame = rowFrame->GetNextRow(), rowIndex++) {
   1.777 +    nsRect rowBounds = rowFrame->GetRect();
   1.778 +    nsRect rowVisualOverflow = rowFrame->GetVisualOverflowRect();
   1.779 +
   1.780 +    bool movedFrame = (rowBounds.y != yOrigin);  
   1.781 +    nscoord rowHeight = (rowInfo[rowIndex].height > 0) ? rowInfo[rowIndex].height : 0;
   1.782 +    
   1.783 +    if (movedFrame || (rowHeight != rowBounds.height)) {
   1.784 +      // Resize/move the row to its final size and position
   1.785 +      if (movedFrame) {
   1.786 +        rowFrame->InvalidateFrameSubtree();
   1.787 +      }
   1.788 +      
   1.789 +      rowFrame->SetRect(nsRect(rowBounds.x, yOrigin, rowBounds.width,
   1.790 +                               rowHeight));
   1.791 +
   1.792 +      nsTableFrame::InvalidateTableFrame(rowFrame, rowBounds, rowVisualOverflow,
   1.793 +                                         false);
   1.794 +    }
   1.795 +    if (movedFrame) {
   1.796 +      nsTableFrame::RePositionViews(rowFrame);
   1.797 +      // XXXbz we don't need to update our overflow area?
   1.798 +    }
   1.799 +    yOrigin += rowHeight + cellSpacingY;
   1.800 +  }
   1.801 +
   1.802 +  if (isPaginated && styleHeightAllocation) {
   1.803 +    // since the row group has a style height, cache the row heights, so next in flows can honor them 
   1.804 +    CacheRowHeightsForPrinting(aPresContext, GetFirstRow());
   1.805 +  }
   1.806 +
   1.807 +  DidResizeRows(aDesiredSize);
   1.808 +
   1.809 +  aDesiredSize.Height() = rowGroupHeight; // Adjust our desired size
   1.810 +}
   1.811 +
   1.812 +nscoord
   1.813 +nsTableRowGroupFrame::CollapseRowGroupIfNecessary(nscoord aYTotalOffset,
   1.814 +                                                  nscoord aWidth)
   1.815 +{
   1.816 +  nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
   1.817 +  const nsStyleVisibility* groupVis = StyleVisibility();
   1.818 +  bool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE == groupVis->mVisible);
   1.819 +  if (collapseGroup) {
   1.820 +    tableFrame->SetNeedToCollapse(true);
   1.821 +  }
   1.822 +
   1.823 +  nsOverflowAreas overflow;
   1.824 +
   1.825 +  nsTableRowFrame* rowFrame= GetFirstRow();
   1.826 +  bool didCollapse = false;
   1.827 +  nscoord yGroupOffset = 0;
   1.828 +  while (rowFrame) {
   1.829 +    yGroupOffset += rowFrame->CollapseRowIfNecessary(yGroupOffset,
   1.830 +                                                     aWidth, collapseGroup,
   1.831 +                                                     didCollapse);
   1.832 +    ConsiderChildOverflow(overflow, rowFrame);
   1.833 +    rowFrame = rowFrame->GetNextRow();
   1.834 +  }
   1.835 +
   1.836 +  nsRect groupRect = GetRect();
   1.837 +  nsRect oldGroupRect = groupRect;
   1.838 +  nsRect oldGroupVisualOverflow = GetVisualOverflowRect();
   1.839 +  
   1.840 +  groupRect.height -= yGroupOffset;
   1.841 +  if (didCollapse) {
   1.842 +    // add back the cellspacing between rowgroups
   1.843 +    groupRect.height += tableFrame->GetCellSpacingY();
   1.844 +  }
   1.845 +
   1.846 +  groupRect.y -= aYTotalOffset;
   1.847 +  groupRect.width = aWidth;
   1.848 +
   1.849 +  if (aYTotalOffset != 0) {
   1.850 +    InvalidateFrameSubtree();
   1.851 +  }
   1.852 +  
   1.853 +  SetRect(groupRect);
   1.854 +  overflow.UnionAllWith(nsRect(0, 0, groupRect.width, groupRect.height));
   1.855 +  FinishAndStoreOverflow(overflow, groupRect.Size());
   1.856 +  nsTableFrame::RePositionViews(this);
   1.857 +  nsTableFrame::InvalidateTableFrame(this, oldGroupRect, oldGroupVisualOverflow,
   1.858 +                                     false);
   1.859 +
   1.860 +  return yGroupOffset;
   1.861 +}
   1.862 +
   1.863 +// Move a child that was skipped during a reflow.
   1.864 +void
   1.865 +nsTableRowGroupFrame::SlideChild(nsRowGroupReflowState& aReflowState,
   1.866 +                                 nsIFrame*              aKidFrame)
   1.867 +{
   1.868 +  // Move the frame if we need to
   1.869 +  nsPoint oldPosition = aKidFrame->GetPosition();
   1.870 +  nsPoint newPosition = oldPosition;
   1.871 +  newPosition.y = aReflowState.y;
   1.872 +  if (oldPosition.y != newPosition.y) {
   1.873 +    aKidFrame->InvalidateFrameSubtree();
   1.874 +    aKidFrame->SetPosition(newPosition);
   1.875 +    nsTableFrame::RePositionViews(aKidFrame);
   1.876 +    aKidFrame->InvalidateFrameSubtree();
   1.877 +  }
   1.878 +}
   1.879 +
   1.880 +// Create a continuing frame, add it to the child list, and then push it
   1.881 +// and the frames that follow
   1.882 +void 
   1.883 +nsTableRowGroupFrame::CreateContinuingRowFrame(nsPresContext& aPresContext,
   1.884 +                                               nsIFrame&      aRowFrame,
   1.885 +                                               nsIFrame**     aContRowFrame)
   1.886 +{
   1.887 +  // XXX what is the row index?
   1.888 +  if (!aContRowFrame) {NS_ASSERTION(false, "bad call"); return;}
   1.889 +  // create the continuing frame which will create continuing cell frames
   1.890 +  *aContRowFrame = aPresContext.PresShell()->FrameConstructor()->
   1.891 +    CreateContinuingFrame(&aPresContext, &aRowFrame, this);
   1.892 +
   1.893 +  // Add the continuing row frame to the child list
   1.894 +  mFrames.InsertFrame(nullptr, &aRowFrame, *aContRowFrame);
   1.895 +
   1.896 +  // Push the continuing row frame and the frames that follow
   1.897 +  PushChildren(*aContRowFrame, &aRowFrame);
   1.898 +}
   1.899 +
   1.900 +// Reflow the cells with rowspan > 1 which originate between aFirstRow
   1.901 +// and end on or after aLastRow. aFirstTruncatedRow is the highest row on the
   1.902 +// page that contains a cell which cannot split on this page 
   1.903 +void
   1.904 +nsTableRowGroupFrame::SplitSpanningCells(nsPresContext&           aPresContext,
   1.905 +                                         const nsHTMLReflowState& aReflowState,
   1.906 +                                         nsTableFrame&            aTable,
   1.907 +                                         nsTableRowFrame&         aFirstRow, 
   1.908 +                                         nsTableRowFrame&         aLastRow,  
   1.909 +                                         bool                     aFirstRowIsTopOfPage,
   1.910 +                                         nscoord                  aSpanningRowBottom,
   1.911 +                                         nsTableRowFrame*&        aContRow,
   1.912 +                                         nsTableRowFrame*&        aFirstTruncatedRow,
   1.913 +                                         nscoord&                 aDesiredHeight)
   1.914 +{
   1.915 +  NS_ASSERTION(aSpanningRowBottom >= 0, "Can't split negative heights");
   1.916 +  aFirstTruncatedRow = nullptr;
   1.917 +  aDesiredHeight     = 0;
   1.918 +
   1.919 +  const bool borderCollapse = aTable.IsBorderCollapse();
   1.920 +  int32_t lastRowIndex = aLastRow.GetRowIndex();
   1.921 +  bool wasLast = false;
   1.922 +  bool haveRowSpan = false;
   1.923 +  // Iterate the rows between aFirstRow and aLastRow
   1.924 +  for (nsTableRowFrame* row = &aFirstRow; !wasLast; row = row->GetNextRow()) {
   1.925 +    wasLast = (row == &aLastRow);
   1.926 +    int32_t rowIndex = row->GetRowIndex();
   1.927 +    nsPoint rowPos = row->GetPosition();
   1.928 +    // Iterate the cells looking for those that have rowspan > 1
   1.929 +    for (nsTableCellFrame* cell = row->GetFirstCell(); cell; cell = cell->GetNextCell()) {
   1.930 +      int32_t rowSpan = aTable.GetEffectiveRowSpan(rowIndex, *cell);
   1.931 +      // Only reflow rowspan > 1 cells which span aLastRow. Those which don't span aLastRow
   1.932 +      // were reflowed correctly during the unconstrained height reflow. 
   1.933 +      if ((rowSpan > 1) && (rowIndex + rowSpan > lastRowIndex)) {
   1.934 +        haveRowSpan = true;
   1.935 +        nsReflowStatus status;
   1.936 +        // Ask the row to reflow the cell to the height of all the rows it spans up through aLastRow
   1.937 +        // aAvailHeight is the space between the row group start and the end of the page
   1.938 +        nscoord cellAvailHeight = aSpanningRowBottom - rowPos.y;
   1.939 +        NS_ASSERTION(cellAvailHeight >= 0, "No space for cell?");
   1.940 +        bool isTopOfPage = (row == &aFirstRow) && aFirstRowIsTopOfPage;
   1.941 +
   1.942 +        nsRect rowRect = row->GetRect();
   1.943 +        nsSize rowAvailSize(aReflowState.AvailableWidth(),
   1.944 +                            std::max(aReflowState.AvailableHeight() - rowRect.y,
   1.945 +                                   0));
   1.946 +        // don't let the available height exceed what
   1.947 +        // CalculateRowHeights set for it
   1.948 +        rowAvailSize.height = std::min(rowAvailSize.height, rowRect.height);
   1.949 +        nsHTMLReflowState rowReflowState(&aPresContext, aReflowState,
   1.950 +                                         row, rowAvailSize,
   1.951 +                                         -1, -1,
   1.952 +                                         nsHTMLReflowState::CALLER_WILL_INIT);
   1.953 +        InitChildReflowState(aPresContext, borderCollapse, rowReflowState);
   1.954 +        rowReflowState.mFlags.mIsTopOfPage = isTopOfPage; // set top of page
   1.955 +
   1.956 +        nscoord cellHeight = row->ReflowCellFrame(&aPresContext, rowReflowState,
   1.957 +                                                  isTopOfPage, cell,
   1.958 +                                                  cellAvailHeight, status);
   1.959 +        aDesiredHeight = std::max(aDesiredHeight, rowPos.y + cellHeight);
   1.960 +        if (NS_FRAME_IS_COMPLETE(status)) {
   1.961 +          if (cellHeight > cellAvailHeight) {
   1.962 +            aFirstTruncatedRow = row;
   1.963 +            if ((row != &aFirstRow) || !aFirstRowIsTopOfPage) {
   1.964 +              // return now, since we will be getting another reflow after either (1) row is 
   1.965 +              // moved to the next page or (2) the row group is moved to the next page
   1.966 +              return;
   1.967 +            }
   1.968 +          }
   1.969 +        }
   1.970 +        else {
   1.971 +          if (!aContRow) {
   1.972 +            CreateContinuingRowFrame(aPresContext, aLastRow, (nsIFrame**)&aContRow);
   1.973 +          }
   1.974 +          if (aContRow) {
   1.975 +            if (row != &aLastRow) {
   1.976 +              // aContRow needs a continuation for cell, since cell spanned into aLastRow 
   1.977 +              // but does not originate there
   1.978 +              nsTableCellFrame* contCell = static_cast<nsTableCellFrame*>(
   1.979 +                aPresContext.PresShell()->FrameConstructor()->
   1.980 +                  CreateContinuingFrame(&aPresContext, cell, &aLastRow));
   1.981 +              int32_t colIndex;
   1.982 +              cell->GetColIndex(colIndex);
   1.983 +              aContRow->InsertCellFrame(contCell, colIndex);
   1.984 +            }
   1.985 +          }
   1.986 +        }
   1.987 +      }
   1.988 +    }
   1.989 +  }
   1.990 +  if (!haveRowSpan) {
   1.991 +    aDesiredHeight = aLastRow.GetRect().YMost();
   1.992 +  }
   1.993 +}
   1.994 +
   1.995 +// Remove the next-in-flow of the row, its cells and their cell blocks. This 
   1.996 +// is necessary in case the row doesn't need a continuation later on or needs 
   1.997 +// a continuation which doesn't have the same number of cells that now exist. 
   1.998 +void
   1.999 +nsTableRowGroupFrame::UndoContinuedRow(nsPresContext*   aPresContext,
  1.1000 +                                       nsTableRowFrame* aRow)
  1.1001 +{
  1.1002 +  if (!aRow) return; // allow null aRow to avoid callers doing null checks
  1.1003 +
  1.1004 +  // rowBefore was the prev-sibling of aRow's next-sibling before aRow was created
  1.1005 +  nsTableRowFrame* rowBefore = (nsTableRowFrame*)aRow->GetPrevInFlow();
  1.1006 +  NS_PRECONDITION(mFrames.ContainsFrame(rowBefore),
  1.1007 +                  "rowBefore not in our frame list?");
  1.1008 +
  1.1009 +  AutoFrameListPtr overflows(aPresContext, StealOverflowFrames());
  1.1010 +  if (!rowBefore || !overflows || overflows->IsEmpty() ||
  1.1011 +      overflows->FirstChild() != aRow) {
  1.1012 +    NS_ERROR("invalid continued row");
  1.1013 +    return;
  1.1014 +  }
  1.1015 +
  1.1016 +  // Destroy aRow, its cells, and their cell blocks. Cell blocks that have split
  1.1017 +  // will not have reflowed yet to pick up content from any overflow lines.
  1.1018 +  overflows->DestroyFrame(aRow);
  1.1019 +
  1.1020 +  // Put the overflow rows into our child list
  1.1021 +  if (!overflows->IsEmpty()) {
  1.1022 +    mFrames.InsertFrames(nullptr, rowBefore, *overflows);
  1.1023 +  }
  1.1024 +}
  1.1025 +
  1.1026 +static nsTableRowFrame* 
  1.1027 +GetRowBefore(nsTableRowFrame& aStartRow,
  1.1028 +             nsTableRowFrame& aRow)
  1.1029 +{
  1.1030 +  nsTableRowFrame* rowBefore = nullptr;
  1.1031 +  for (nsTableRowFrame* sib = &aStartRow; sib && (sib != &aRow); sib = sib->GetNextRow()) {
  1.1032 +    rowBefore = sib;
  1.1033 +  }
  1.1034 +  return rowBefore;
  1.1035 +}
  1.1036 +
  1.1037 +nsresult
  1.1038 +nsTableRowGroupFrame::SplitRowGroup(nsPresContext*           aPresContext,
  1.1039 +                                    nsHTMLReflowMetrics&     aDesiredSize,
  1.1040 +                                    const nsHTMLReflowState& aReflowState,
  1.1041 +                                    nsTableFrame*            aTableFrame,
  1.1042 +                                    nsReflowStatus&          aStatus,
  1.1043 +                                    bool                     aRowForcedPageBreak)
  1.1044 +{
  1.1045 +  NS_PRECONDITION(aPresContext->IsPaginated(), "SplitRowGroup currently supports only paged media"); 
  1.1046 +
  1.1047 +  nsresult rv = NS_OK;
  1.1048 +  nsTableRowFrame* prevRowFrame = nullptr;
  1.1049 +  aDesiredSize.Height() = 0;
  1.1050 +
  1.1051 +  nscoord availWidth  = aReflowState.AvailableWidth();
  1.1052 +  nscoord availHeight = aReflowState.AvailableHeight();
  1.1053 +  
  1.1054 +  const bool borderCollapse = aTableFrame->IsBorderCollapse();
  1.1055 +  nscoord cellSpacingY = aTableFrame->GetCellSpacingY();
  1.1056 +  
  1.1057 +  // get the page height
  1.1058 +  nscoord pageHeight = aPresContext->GetPageSize().height;
  1.1059 +  NS_ASSERTION(pageHeight != NS_UNCONSTRAINEDSIZE, 
  1.1060 +               "The table shouldn't be split when there should be space");
  1.1061 +
  1.1062 +  bool isTopOfPage = aReflowState.mFlags.mIsTopOfPage;
  1.1063 +  nsTableRowFrame* firstRowThisPage = GetFirstRow();
  1.1064 +
  1.1065 +  // Need to dirty the table's geometry, or else the row might skip
  1.1066 +  // reflowing its cell as an optimization.
  1.1067 +  aTableFrame->SetGeometryDirty();
  1.1068 +
  1.1069 +  // Walk each of the row frames looking for the first row frame that doesn't fit 
  1.1070 +  // in the available space
  1.1071 +  for (nsTableRowFrame* rowFrame = firstRowThisPage; rowFrame; rowFrame = rowFrame->GetNextRow()) {
  1.1072 +    bool rowIsOnPage = true;
  1.1073 +    nsRect rowRect = rowFrame->GetRect();
  1.1074 +    // See if the row fits on this page
  1.1075 +    if (rowRect.YMost() > availHeight) {
  1.1076 +      nsTableRowFrame* contRow = nullptr;
  1.1077 +      // Reflow the row in the availabe space and have it split if it is the 1st
  1.1078 +      // row (on the page) or there is at least 5% of the current page available 
  1.1079 +      // XXX this 5% should be made a preference 
  1.1080 +      if (!prevRowFrame || (availHeight - aDesiredSize.Height() > pageHeight / 20)) { 
  1.1081 +        nsSize availSize(availWidth, std::max(availHeight - rowRect.y, 0));
  1.1082 +        // don't let the available height exceed what CalculateRowHeights set for it
  1.1083 +        availSize.height = std::min(availSize.height, rowRect.height);
  1.1084 +
  1.1085 +        nsHTMLReflowState rowReflowState(aPresContext, aReflowState,
  1.1086 +                                         rowFrame, availSize,
  1.1087 +                                         -1, -1,
  1.1088 +                                         nsHTMLReflowState::CALLER_WILL_INIT);
  1.1089 +                                         
  1.1090 +        InitChildReflowState(*aPresContext, borderCollapse, rowReflowState);
  1.1091 +        rowReflowState.mFlags.mIsTopOfPage = isTopOfPage; // set top of page
  1.1092 +        nsHTMLReflowMetrics rowMetrics(aReflowState);
  1.1093 +
  1.1094 +        // Get the old size before we reflow.
  1.1095 +        nsRect oldRowRect = rowFrame->GetRect();
  1.1096 +        nsRect oldRowVisualOverflow = rowFrame->GetVisualOverflowRect();
  1.1097 +
  1.1098 +        // Reflow the cell with the constrained height. A cell with rowspan >1 will get this
  1.1099 +        // reflow later during SplitSpanningCells.
  1.1100 +        rv = ReflowChild(rowFrame, aPresContext, rowMetrics, rowReflowState,
  1.1101 +                         0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus);
  1.1102 +        if (NS_FAILED(rv)) return rv;
  1.1103 +        rowFrame->SetSize(nsSize(rowMetrics.Width(), rowMetrics.Height()));
  1.1104 +        rowFrame->DidReflow(aPresContext, nullptr, nsDidReflowStatus::FINISHED);
  1.1105 +        rowFrame->DidResize();
  1.1106 +
  1.1107 +        if (!aRowForcedPageBreak && !NS_FRAME_IS_FULLY_COMPLETE(aStatus) &&
  1.1108 +            ShouldAvoidBreakInside(aReflowState)) {
  1.1109 +          aStatus = NS_INLINE_LINE_BREAK_BEFORE();
  1.1110 +          break;
  1.1111 +        }
  1.1112 +
  1.1113 +        nsTableFrame::InvalidateTableFrame(rowFrame, oldRowRect,
  1.1114 +                                           oldRowVisualOverflow,
  1.1115 +                                           false);
  1.1116 +
  1.1117 +        if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
  1.1118 +          // The row frame is incomplete and all of the rowspan 1 cells' block frames split
  1.1119 +          if ((rowMetrics.Height() <= rowReflowState.AvailableHeight()) || isTopOfPage) {
  1.1120 +            // The row stays on this page because either it split ok or we're on the top of page.
  1.1121 +            // If top of page and the height exceeded the avail height, then there will be data loss
  1.1122 +            NS_ASSERTION(rowMetrics.Height() <= rowReflowState.AvailableHeight(), 
  1.1123 +                         "data loss - incomplete row needed more height than available, on top of page");
  1.1124 +            CreateContinuingRowFrame(*aPresContext, *rowFrame, (nsIFrame**)&contRow);
  1.1125 +            if (contRow) {
  1.1126 +              aDesiredSize.Height() += rowMetrics.Height();
  1.1127 +              if (prevRowFrame) 
  1.1128 +                aDesiredSize.Height() += cellSpacingY;
  1.1129 +            }
  1.1130 +            else return NS_ERROR_NULL_POINTER;
  1.1131 +          }
  1.1132 +          else {
  1.1133 +            // Put the row on the next page to give it more height 
  1.1134 +            rowIsOnPage = false;
  1.1135 +          }
  1.1136 +        } 
  1.1137 +        else {
  1.1138 +          // The row frame is complete because either (1) its minimum height is greater than the 
  1.1139 +          // available height we gave it, or (2) it may have been given a larger height through 
  1.1140 +          // style than its content, or (3) it contains a rowspan >1 cell which hasn't been
  1.1141 +          // reflowed with a constrained height yet (we will find out when SplitSpanningCells is
  1.1142 +          // called below)
  1.1143 +          if (rowMetrics.Height() > availSize.height ||
  1.1144 +              (NS_INLINE_IS_BREAK_BEFORE(aStatus) && !aRowForcedPageBreak)) {
  1.1145 +            // cases (1) and (2)
  1.1146 +            if (isTopOfPage) { 
  1.1147 +              // We're on top of the page, so keep the row on this page. There will be data loss.
  1.1148 +              // Push the row frame that follows
  1.1149 +              nsTableRowFrame* nextRowFrame = rowFrame->GetNextRow();
  1.1150 +              if (nextRowFrame) {
  1.1151 +                aStatus = NS_FRAME_NOT_COMPLETE;
  1.1152 +              }
  1.1153 +              aDesiredSize.Height() += rowMetrics.Height();
  1.1154 +              if (prevRowFrame) 
  1.1155 +                aDesiredSize.Height() += cellSpacingY;
  1.1156 +              NS_WARNING("data loss - complete row needed more height than available, on top of page");
  1.1157 +            }
  1.1158 +            else {
  1.1159 +              // We're not on top of the page, so put the row on the next page to give it more height 
  1.1160 +              rowIsOnPage = false;
  1.1161 +            }
  1.1162 +          }
  1.1163 +        }
  1.1164 +      } //if (!prevRowFrame || (availHeight - aDesiredSize.Height() > pageHeight / 20))
  1.1165 +      else { 
  1.1166 +        // put the row on the next page to give it more height
  1.1167 +        rowIsOnPage = false;
  1.1168 +      }
  1.1169 +
  1.1170 +      nsTableRowFrame* lastRowThisPage = rowFrame;
  1.1171 +      nscoord spanningRowBottom = availHeight;
  1.1172 +      if (!rowIsOnPage) {
  1.1173 +        NS_ASSERTION(!contRow, "We should not have created a continuation if none of this row fits");
  1.1174 +        if (!aRowForcedPageBreak && ShouldAvoidBreakInside(aReflowState)) {
  1.1175 +          aStatus = NS_INLINE_LINE_BREAK_BEFORE();
  1.1176 +          break;
  1.1177 +        }
  1.1178 +        if (prevRowFrame) {
  1.1179 +          spanningRowBottom = prevRowFrame->GetRect().YMost();
  1.1180 +          lastRowThisPage = prevRowFrame;
  1.1181 +          isTopOfPage = (lastRowThisPage == firstRowThisPage) && aReflowState.mFlags.mIsTopOfPage;
  1.1182 +          aStatus = NS_FRAME_NOT_COMPLETE;
  1.1183 +        }
  1.1184 +        else {
  1.1185 +          // We can't push children, so let our parent reflow us again with more space
  1.1186 +          aDesiredSize.Height() = rowRect.YMost();
  1.1187 +          aStatus = NS_FRAME_COMPLETE;
  1.1188 +          break;
  1.1189 +        }
  1.1190 +      }
  1.1191 +      // reflow the cells with rowspan >1 that occur on the page
  1.1192 +
  1.1193 +      nsTableRowFrame* firstTruncatedRow;
  1.1194 +      nscoord yMost;
  1.1195 +      SplitSpanningCells(*aPresContext, aReflowState, *aTableFrame, *firstRowThisPage,
  1.1196 +                         *lastRowThisPage, aReflowState.mFlags.mIsTopOfPage, spanningRowBottom, contRow, 
  1.1197 +                         firstTruncatedRow, yMost);
  1.1198 +      if (firstTruncatedRow) {
  1.1199 +        // A rowspan >1 cell did not fit (and could not split) in the space we gave it
  1.1200 +        if (firstTruncatedRow == firstRowThisPage) {
  1.1201 +          if (aReflowState.mFlags.mIsTopOfPage) {
  1.1202 +            NS_WARNING("data loss in a row spanned cell");
  1.1203 +          }
  1.1204 +          else {
  1.1205 +            // We can't push children, so let our parent reflow us again with more space
  1.1206 +            aDesiredSize.Height() = rowRect.YMost();
  1.1207 +            aStatus = NS_FRAME_COMPLETE;
  1.1208 +            UndoContinuedRow(aPresContext, contRow);
  1.1209 +            contRow = nullptr;
  1.1210 +          }
  1.1211 +        }
  1.1212 +        else { // (firstTruncatedRow != firstRowThisPage)
  1.1213 +          // Try to put firstTruncateRow on the next page 
  1.1214 +          nsTableRowFrame* rowBefore = ::GetRowBefore(*firstRowThisPage, *firstTruncatedRow);
  1.1215 +          nscoord oldSpanningRowBottom = spanningRowBottom;
  1.1216 +          spanningRowBottom = rowBefore->GetRect().YMost();
  1.1217 +
  1.1218 +          UndoContinuedRow(aPresContext, contRow);
  1.1219 +          contRow = nullptr;
  1.1220 +          nsTableRowFrame* oldLastRowThisPage = lastRowThisPage;
  1.1221 +          lastRowThisPage = rowBefore;
  1.1222 +          aStatus = NS_FRAME_NOT_COMPLETE;
  1.1223 +
  1.1224 +          // Call SplitSpanningCells again with rowBefore as the last row on the page
  1.1225 +          SplitSpanningCells(*aPresContext, aReflowState, *aTableFrame, 
  1.1226 +                             *firstRowThisPage, *rowBefore, aReflowState.mFlags.mIsTopOfPage, 
  1.1227 +                             spanningRowBottom, contRow, firstTruncatedRow, aDesiredSize.Height());
  1.1228 +          if (firstTruncatedRow) {
  1.1229 +            if (aReflowState.mFlags.mIsTopOfPage) {
  1.1230 +              // We were better off with the 1st call to SplitSpanningCells, do it again
  1.1231 +              UndoContinuedRow(aPresContext, contRow);
  1.1232 +              contRow = nullptr;
  1.1233 +              lastRowThisPage = oldLastRowThisPage;
  1.1234 +              spanningRowBottom = oldSpanningRowBottom;
  1.1235 +              SplitSpanningCells(*aPresContext, aReflowState, *aTableFrame, *firstRowThisPage,
  1.1236 +                                 *lastRowThisPage, aReflowState.mFlags.mIsTopOfPage, spanningRowBottom, contRow, 
  1.1237 +                                 firstTruncatedRow, aDesiredSize.Height());
  1.1238 +              NS_WARNING("data loss in a row spanned cell");
  1.1239 +            }
  1.1240 +            else {
  1.1241 +              // Let our parent reflow us again with more space
  1.1242 +              aDesiredSize.Height() = rowRect.YMost();
  1.1243 +              aStatus = NS_FRAME_COMPLETE;
  1.1244 +              UndoContinuedRow(aPresContext, contRow);
  1.1245 +              contRow = nullptr;
  1.1246 +            }
  1.1247 +          }
  1.1248 +        } // if (firstTruncatedRow == firstRowThisPage)
  1.1249 +      } // if (firstTruncatedRow)
  1.1250 +      else {
  1.1251 +        aDesiredSize.Height() = std::max(aDesiredSize.Height(), yMost);
  1.1252 +        if (contRow) {
  1.1253 +          aStatus = NS_FRAME_NOT_COMPLETE;
  1.1254 +        }
  1.1255 +      }
  1.1256 +      if (NS_FRAME_IS_NOT_COMPLETE(aStatus) && !contRow) {
  1.1257 +        nsTableRowFrame* nextRow = lastRowThisPage->GetNextRow();
  1.1258 +        if (nextRow) {
  1.1259 +          PushChildren(nextRow, lastRowThisPage);
  1.1260 +        }
  1.1261 +      }
  1.1262 +      break;
  1.1263 +    } // if (rowRect.YMost() > availHeight)
  1.1264 +    else { 
  1.1265 +      aDesiredSize.Height() = rowRect.YMost();
  1.1266 +      prevRowFrame = rowFrame;
  1.1267 +      // see if there is a page break after the row
  1.1268 +      nsTableRowFrame* nextRow = rowFrame->GetNextRow();
  1.1269 +      if (nextRow && nsTableFrame::PageBreakAfter(rowFrame, nextRow)) {
  1.1270 +        PushChildren(nextRow, rowFrame);
  1.1271 +        aStatus = NS_FRAME_NOT_COMPLETE;
  1.1272 +        break;
  1.1273 +      }
  1.1274 +    }
  1.1275 +    // after the 1st row that has a height, we can't be on top
  1.1276 +    // of the page anymore.
  1.1277 +    isTopOfPage = isTopOfPage && rowRect.YMost() == 0;
  1.1278 +  }
  1.1279 +  return NS_OK;
  1.1280 +}
  1.1281 +
  1.1282 +/** Layout the entire row group.
  1.1283 +  * This method stacks rows vertically according to HTML 4.0 rules.
  1.1284 +  * Rows are responsible for layout of their children.
  1.1285 +  */
  1.1286 +nsresult
  1.1287 +nsTableRowGroupFrame::Reflow(nsPresContext*           aPresContext,
  1.1288 +                             nsHTMLReflowMetrics&     aDesiredSize,
  1.1289 +                             const nsHTMLReflowState& aReflowState,
  1.1290 +                             nsReflowStatus&          aStatus)
  1.1291 +{
  1.1292 +  DO_GLOBAL_REFLOW_COUNT("nsTableRowGroupFrame");
  1.1293 +  DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
  1.1294 +
  1.1295 +  nsresult rv = NS_OK;
  1.1296 +  aStatus     = NS_FRAME_COMPLETE;
  1.1297 +
  1.1298 +  // Row geometry may be going to change so we need to invalidate any row cursor.
  1.1299 +  ClearRowCursor();
  1.1300 +
  1.1301 +  // see if a special height reflow needs to occur due to having a pct height
  1.1302 +  nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState);
  1.1303 +
  1.1304 +  nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
  1.1305 +  nsRowGroupReflowState state(aReflowState, tableFrame);
  1.1306 +  const nsStyleVisibility* groupVis = StyleVisibility();
  1.1307 +  bool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE == groupVis->mVisible);
  1.1308 +  if (collapseGroup) {
  1.1309 +    tableFrame->SetNeedToCollapse(true);
  1.1310 +  }
  1.1311 +
  1.1312 +  // Check for an overflow list
  1.1313 +  MoveOverflowToChildList();
  1.1314 +
  1.1315 +  // Reflow the existing frames. 
  1.1316 +  bool splitDueToPageBreak = false;
  1.1317 +  rv = ReflowChildren(aPresContext, aDesiredSize, state, aStatus,
  1.1318 +                      &splitDueToPageBreak);
  1.1319 +
  1.1320 +  // See if all the frames fit. Do not try to split anything if we're
  1.1321 +  // not paginated ... we can't split across columns yet.
  1.1322 +  if (aReflowState.mFlags.mTableIsSplittable &&
  1.1323 +      NS_UNCONSTRAINEDSIZE != aReflowState.AvailableHeight() &&
  1.1324 +      (NS_FRAME_NOT_COMPLETE == aStatus || splitDueToPageBreak || 
  1.1325 +       aDesiredSize.Height() > aReflowState.AvailableHeight())) {
  1.1326 +    // Nope, find a place to split the row group 
  1.1327 +    bool specialReflow = (bool)aReflowState.mFlags.mSpecialHeightReflow;
  1.1328 +    ((nsHTMLReflowState::ReflowStateFlags&)aReflowState.mFlags).mSpecialHeightReflow = false;
  1.1329 +
  1.1330 +    SplitRowGroup(aPresContext, aDesiredSize, aReflowState, tableFrame, aStatus,
  1.1331 +                  splitDueToPageBreak);
  1.1332 +
  1.1333 +    ((nsHTMLReflowState::ReflowStateFlags&)aReflowState.mFlags).mSpecialHeightReflow = specialReflow;
  1.1334 +  }
  1.1335 +
  1.1336 +  // XXXmats The following is just bogus.  We leave it here for now because
  1.1337 +  // ReflowChildren should pull up rows from our next-in-flow before returning
  1.1338 +  // a Complete status, but doesn't (bug 804888).
  1.1339 +  if (GetNextInFlow() && GetNextInFlow()->GetFirstPrincipalChild()) {
  1.1340 +    NS_FRAME_SET_INCOMPLETE(aStatus);
  1.1341 +  }
  1.1342 +
  1.1343 +  SetHasStyleHeight((NS_UNCONSTRAINEDSIZE != aReflowState.ComputedHeight()) &&
  1.1344 +                    (aReflowState.ComputedHeight() > 0)); 
  1.1345 +  
  1.1346 +  // just set our width to what was available. The table will calculate the width and not use our value.
  1.1347 +  aDesiredSize.Width() = aReflowState.AvailableWidth();
  1.1348 +
  1.1349 +  aDesiredSize.UnionOverflowAreasWithDesiredBounds();
  1.1350 +
  1.1351 +  // If our parent is in initial reflow, it'll handle invalidating our
  1.1352 +  // entire overflow rect.
  1.1353 +  if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW) &&
  1.1354 +      nsSize(aDesiredSize.Width(), aDesiredSize.Height()) != mRect.Size()) {
  1.1355 +    InvalidateFrame();
  1.1356 +  }
  1.1357 +  
  1.1358 +  FinishAndStoreOverflow(&aDesiredSize);
  1.1359 +  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
  1.1360 +  return rv;
  1.1361 +}
  1.1362 +
  1.1363 +bool
  1.1364 +nsTableRowGroupFrame::UpdateOverflow()
  1.1365 +{
  1.1366 +  // Row cursor invariants depend on the visual overflow area of the rows,
  1.1367 +  // which may have changed, so we need to clear the cursor now.
  1.1368 +  ClearRowCursor();
  1.1369 +  return nsContainerFrame::UpdateOverflow();
  1.1370 +}
  1.1371 +
  1.1372 +/* virtual */ void
  1.1373 +nsTableRowGroupFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
  1.1374 +{
  1.1375 +  nsContainerFrame::DidSetStyleContext(aOldStyleContext);
  1.1376 +
  1.1377 +  if (!aOldStyleContext) //avoid this on init
  1.1378 +    return;
  1.1379 +     
  1.1380 +  nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
  1.1381 +  if (tableFrame->IsBorderCollapse() &&
  1.1382 +      tableFrame->BCRecalcNeeded(aOldStyleContext, StyleContext())) {
  1.1383 +    nsIntRect damageArea(0, GetStartRowIndex(), tableFrame->GetColCount(),
  1.1384 +                         GetRowCount());
  1.1385 +    tableFrame->AddBCDamageArea(damageArea);
  1.1386 +  }
  1.1387 +}
  1.1388 +
  1.1389 +nsresult
  1.1390 +nsTableRowGroupFrame::AppendFrames(ChildListID     aListID,
  1.1391 +                                   nsFrameList&    aFrameList)
  1.1392 +{
  1.1393 +  NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
  1.1394 +
  1.1395 +  ClearRowCursor();
  1.1396 +
  1.1397 +  // collect the new row frames in an array
  1.1398 +  // XXXbz why are we doing the QI stuff?  There shouldn't be any non-rows here.
  1.1399 +  nsAutoTArray<nsTableRowFrame*, 8> rows;
  1.1400 +  for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
  1.1401 +    nsTableRowFrame *rowFrame = do_QueryFrame(e.get());
  1.1402 +    NS_ASSERTION(rowFrame, "Unexpected frame; frame constructor screwed up");
  1.1403 +    if (rowFrame) {
  1.1404 +      NS_ASSERTION(NS_STYLE_DISPLAY_TABLE_ROW ==
  1.1405 +                     e.get()->StyleDisplay()->mDisplay,
  1.1406 +                   "wrong display type on rowframe");      
  1.1407 +      rows.AppendElement(rowFrame);
  1.1408 +    }
  1.1409 +  }
  1.1410 +
  1.1411 +  int32_t rowIndex = GetRowCount();
  1.1412 +  // Append the frames to the sibling chain
  1.1413 +  mFrames.AppendFrames(nullptr, aFrameList);
  1.1414 +
  1.1415 +  if (rows.Length() > 0) {
  1.1416 +    nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
  1.1417 +    tableFrame->AppendRows(this, rowIndex, rows);
  1.1418 +    PresContext()->PresShell()->
  1.1419 +      FrameNeedsReflow(this, nsIPresShell::eTreeChange,
  1.1420 +                       NS_FRAME_HAS_DIRTY_CHILDREN);
  1.1421 +    tableFrame->SetGeometryDirty();
  1.1422 +  }
  1.1423 +
  1.1424 +  return NS_OK;
  1.1425 +}
  1.1426 +
  1.1427 +nsresult
  1.1428 +nsTableRowGroupFrame::InsertFrames(ChildListID     aListID,
  1.1429 +                                   nsIFrame*       aPrevFrame,
  1.1430 +                                   nsFrameList&    aFrameList)
  1.1431 +{
  1.1432 +  NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
  1.1433 +  NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
  1.1434 +               "inserting after sibling frame with different parent");
  1.1435 +
  1.1436 +  ClearRowCursor();
  1.1437 +
  1.1438 +  // collect the new row frames in an array
  1.1439 +  // XXXbz why are we doing the QI stuff?  There shouldn't be any non-rows here.
  1.1440 +  nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
  1.1441 +  nsTArray<nsTableRowFrame*> rows;
  1.1442 +  bool gotFirstRow = false;
  1.1443 +  for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
  1.1444 +    nsTableRowFrame *rowFrame = do_QueryFrame(e.get());
  1.1445 +    NS_ASSERTION(rowFrame, "Unexpected frame; frame constructor screwed up");
  1.1446 +    if (rowFrame) {
  1.1447 +      NS_ASSERTION(NS_STYLE_DISPLAY_TABLE_ROW ==
  1.1448 +                     e.get()->StyleDisplay()->mDisplay,
  1.1449 +                   "wrong display type on rowframe");      
  1.1450 +      rows.AppendElement(rowFrame);
  1.1451 +      if (!gotFirstRow) {
  1.1452 +        rowFrame->SetFirstInserted(true);
  1.1453 +        gotFirstRow = true;
  1.1454 +        tableFrame->SetRowInserted(true);
  1.1455 +      }
  1.1456 +    }
  1.1457 +  }
  1.1458 +
  1.1459 +  int32_t startRowIndex = GetStartRowIndex();
  1.1460 +  // Insert the frames in the sibling chain
  1.1461 +  mFrames.InsertFrames(nullptr, aPrevFrame, aFrameList);
  1.1462 +
  1.1463 +  int32_t numRows = rows.Length();
  1.1464 +  if (numRows > 0) {
  1.1465 +    nsTableRowFrame* prevRow = (nsTableRowFrame *)nsTableFrame::GetFrameAtOrBefore(this, aPrevFrame, nsGkAtoms::tableRowFrame);
  1.1466 +    int32_t rowIndex = (prevRow) ? prevRow->GetRowIndex() + 1 : startRowIndex;
  1.1467 +    tableFrame->InsertRows(this, rows, rowIndex, true);
  1.1468 +
  1.1469 +    PresContext()->PresShell()->
  1.1470 +      FrameNeedsReflow(this, nsIPresShell::eTreeChange,
  1.1471 +                       NS_FRAME_HAS_DIRTY_CHILDREN);
  1.1472 +    tableFrame->SetGeometryDirty();
  1.1473 +  }
  1.1474 +  return NS_OK;
  1.1475 +}
  1.1476 +
  1.1477 +nsresult
  1.1478 +nsTableRowGroupFrame::RemoveFrame(ChildListID     aListID,
  1.1479 +                                  nsIFrame*       aOldFrame)
  1.1480 +{
  1.1481 +  NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
  1.1482 +
  1.1483 +  ClearRowCursor();
  1.1484 +
  1.1485 +  nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
  1.1486 +  // XXX why are we doing the QI stuff?  There shouldn't be any non-rows here.
  1.1487 +  nsTableRowFrame* rowFrame = do_QueryFrame(aOldFrame);
  1.1488 +  if (rowFrame) {
  1.1489 +    // remove the rows from the table (and flag a rebalance)
  1.1490 +    tableFrame->RemoveRows(*rowFrame, 1, true);
  1.1491 +
  1.1492 +    PresContext()->PresShell()->
  1.1493 +      FrameNeedsReflow(this, nsIPresShell::eTreeChange,
  1.1494 +                       NS_FRAME_HAS_DIRTY_CHILDREN);
  1.1495 +    tableFrame->SetGeometryDirty();
  1.1496 +  }
  1.1497 +  mFrames.DestroyFrame(aOldFrame);
  1.1498 +
  1.1499 +  return NS_OK;
  1.1500 +}
  1.1501 +
  1.1502 +/* virtual */ nsMargin
  1.1503 +nsTableRowGroupFrame::GetUsedMargin() const
  1.1504 +{
  1.1505 +  return nsMargin(0,0,0,0);
  1.1506 +}
  1.1507 +
  1.1508 +/* virtual */ nsMargin
  1.1509 +nsTableRowGroupFrame::GetUsedBorder() const
  1.1510 +{
  1.1511 +  return nsMargin(0,0,0,0);
  1.1512 +}
  1.1513 +
  1.1514 +/* virtual */ nsMargin
  1.1515 +nsTableRowGroupFrame::GetUsedPadding() const
  1.1516 +{
  1.1517 +  return nsMargin(0,0,0,0);
  1.1518 +}
  1.1519 +
  1.1520 +nscoord 
  1.1521 +nsTableRowGroupFrame::GetHeightBasis(const nsHTMLReflowState& aReflowState)
  1.1522 +{
  1.1523 +  nscoord result = 0;
  1.1524 +  nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
  1.1525 +  if ((aReflowState.ComputedHeight() > 0) && (aReflowState.ComputedHeight() < NS_UNCONSTRAINEDSIZE)) {
  1.1526 +    nscoord cellSpacing = std::max(0, GetRowCount() - 1) * tableFrame->GetCellSpacingY();
  1.1527 +    result = aReflowState.ComputedHeight() - cellSpacing;
  1.1528 +  }
  1.1529 +  else {
  1.1530 +    const nsHTMLReflowState* parentRS = aReflowState.parentReflowState;
  1.1531 +    if (parentRS && (tableFrame != parentRS->frame)) {
  1.1532 +      parentRS = parentRS->parentReflowState;
  1.1533 +    }
  1.1534 +    if (parentRS && (tableFrame == parentRS->frame) && 
  1.1535 +        (parentRS->ComputedHeight() > 0) && (parentRS->ComputedHeight() < NS_UNCONSTRAINEDSIZE)) {
  1.1536 +      nscoord cellSpacing = std::max(0, tableFrame->GetRowCount() + 1) * tableFrame->GetCellSpacingY();
  1.1537 +      result = parentRS->ComputedHeight() - cellSpacing;
  1.1538 +    }
  1.1539 +  }
  1.1540 +
  1.1541 +  return result;
  1.1542 +}
  1.1543 +
  1.1544 +bool
  1.1545 +nsTableRowGroupFrame::IsSimpleRowFrame(nsTableFrame* aTableFrame,
  1.1546 +                                       nsIFrame*     aFrame)
  1.1547 +{
  1.1548 +  // Make sure it's a row frame and not a row group frame
  1.1549 +  nsTableRowFrame *rowFrame = do_QueryFrame(aFrame);
  1.1550 +  if (rowFrame) {
  1.1551 +    int32_t rowIndex = rowFrame->GetRowIndex();
  1.1552 +    
  1.1553 +    // It's a simple row frame if there are no cells that span into or
  1.1554 +    // across the row
  1.1555 +    int32_t numEffCols = aTableFrame->GetEffectiveColCount();
  1.1556 +    if (!aTableFrame->RowIsSpannedInto(rowIndex, numEffCols) &&
  1.1557 +        !aTableFrame->RowHasSpanningCells(rowIndex, numEffCols)) {
  1.1558 +      return true;
  1.1559 +    }
  1.1560 +  }
  1.1561 +
  1.1562 +  return false;
  1.1563 +}
  1.1564 +
  1.1565 +nsIAtom*
  1.1566 +nsTableRowGroupFrame::GetType() const
  1.1567 +{
  1.1568 +  return nsGkAtoms::tableRowGroupFrame;
  1.1569 +}
  1.1570 +
  1.1571 +/** find page break before the first row **/
  1.1572 +bool 
  1.1573 +nsTableRowGroupFrame::HasInternalBreakBefore() const
  1.1574 +{
  1.1575 + nsIFrame* firstChild = mFrames.FirstChild(); 
  1.1576 +  if (!firstChild)
  1.1577 +    return false;
  1.1578 +  return firstChild->StyleDisplay()->mBreakBefore;
  1.1579 +}
  1.1580 +
  1.1581 +/** find page break after the last row **/
  1.1582 +bool 
  1.1583 +nsTableRowGroupFrame::HasInternalBreakAfter() const
  1.1584 +{
  1.1585 +  nsIFrame* lastChild = mFrames.LastChild(); 
  1.1586 +  if (!lastChild)
  1.1587 +    return false;
  1.1588 +  return lastChild->StyleDisplay()->mBreakAfter;
  1.1589 +}
  1.1590 +/* ----- global methods ----- */
  1.1591 +
  1.1592 +nsIFrame*
  1.1593 +NS_NewTableRowGroupFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
  1.1594 +{
  1.1595 +  return new (aPresShell) nsTableRowGroupFrame(aContext);
  1.1596 +}
  1.1597 +
  1.1598 +NS_IMPL_FRAMEARENA_HELPERS(nsTableRowGroupFrame)
  1.1599 +
  1.1600 +#ifdef DEBUG_FRAME_DUMP
  1.1601 +nsresult
  1.1602 +nsTableRowGroupFrame::GetFrameName(nsAString& aResult) const
  1.1603 +{
  1.1604 +  return MakeFrameName(NS_LITERAL_STRING("TableRowGroup"), aResult);
  1.1605 +}
  1.1606 +#endif
  1.1607 +
  1.1608 +nsMargin* 
  1.1609 +nsTableRowGroupFrame::GetBCBorderWidth(nsMargin& aBorder)
  1.1610 +{
  1.1611 +  aBorder.left = aBorder.right = aBorder.top = aBorder.bottom = 0;
  1.1612 +
  1.1613 +  nsTableRowFrame* firstRowFrame = nullptr;
  1.1614 +  nsTableRowFrame* lastRowFrame = nullptr;
  1.1615 +  for (nsTableRowFrame* rowFrame = GetFirstRow(); rowFrame; rowFrame = rowFrame->GetNextRow()) {
  1.1616 +    if (!firstRowFrame) {
  1.1617 +      firstRowFrame = rowFrame;
  1.1618 +    }
  1.1619 +    lastRowFrame = rowFrame;
  1.1620 +  }
  1.1621 +  if (firstRowFrame) {
  1.1622 +    aBorder.top    = nsPresContext::CSSPixelsToAppUnits(firstRowFrame->GetTopBCBorderWidth());
  1.1623 +    aBorder.bottom = nsPresContext::CSSPixelsToAppUnits(lastRowFrame->GetBottomBCBorderWidth());
  1.1624 +  }
  1.1625 +
  1.1626 +  return &aBorder;
  1.1627 +}
  1.1628 +
  1.1629 +void nsTableRowGroupFrame::SetContinuousBCBorderWidth(uint8_t     aForSide,
  1.1630 +                                                      BCPixelSize aPixelValue)
  1.1631 +{
  1.1632 +  switch (aForSide) {
  1.1633 +    case NS_SIDE_RIGHT:
  1.1634 +      mRightContBorderWidth = aPixelValue;
  1.1635 +      return;
  1.1636 +    case NS_SIDE_BOTTOM:
  1.1637 +      mBottomContBorderWidth = aPixelValue;
  1.1638 +      return;
  1.1639 +    case NS_SIDE_LEFT:
  1.1640 +      mLeftContBorderWidth = aPixelValue;
  1.1641 +      return;
  1.1642 +    default:
  1.1643 +      NS_ERROR("invalid NS_SIDE argument");
  1.1644 +  }
  1.1645 +}
  1.1646 +
  1.1647 +//nsILineIterator methods
  1.1648 +int32_t
  1.1649 +nsTableRowGroupFrame::GetNumLines()
  1.1650 +{
  1.1651 +  return GetRowCount();
  1.1652 +}
  1.1653 +
  1.1654 +bool
  1.1655 +nsTableRowGroupFrame::GetDirection()
  1.1656 +{
  1.1657 +  nsTableFrame* table = nsTableFrame::GetTableFrame(this);
  1.1658 +  return (NS_STYLE_DIRECTION_RTL ==
  1.1659 +          table->StyleVisibility()->mDirection);
  1.1660 +}
  1.1661 +  
  1.1662 +NS_IMETHODIMP
  1.1663 +nsTableRowGroupFrame::GetLine(int32_t    aLineNumber, 
  1.1664 +                              nsIFrame** aFirstFrameOnLine, 
  1.1665 +                              int32_t*   aNumFramesOnLine,
  1.1666 +                              nsRect&    aLineBounds, 
  1.1667 +                              uint32_t*  aLineFlags)
  1.1668 +{
  1.1669 +  NS_ENSURE_ARG_POINTER(aFirstFrameOnLine);
  1.1670 +  NS_ENSURE_ARG_POINTER(aNumFramesOnLine);
  1.1671 +  NS_ENSURE_ARG_POINTER(aLineFlags);
  1.1672 +
  1.1673 +  nsTableFrame* table = nsTableFrame::GetTableFrame(this);
  1.1674 +  nsTableCellMap* cellMap = table->GetCellMap();
  1.1675 +
  1.1676 +  *aLineFlags = 0;
  1.1677 +  *aFirstFrameOnLine = nullptr;
  1.1678 +  *aNumFramesOnLine = 0;
  1.1679 +  aLineBounds.SetRect(0, 0, 0, 0);
  1.1680 +  
  1.1681 +  if ((aLineNumber < 0) || (aLineNumber >=  GetRowCount())) {
  1.1682 +    return NS_OK;
  1.1683 +  }
  1.1684 +  aLineNumber += GetStartRowIndex(); 
  1.1685 +
  1.1686 +  *aNumFramesOnLine = cellMap->GetNumCellsOriginatingInRow(aLineNumber);
  1.1687 +  if (*aNumFramesOnLine == 0) {
  1.1688 +    return NS_OK;
  1.1689 +  }
  1.1690 +  int32_t colCount = table->GetColCount();
  1.1691 +  for (int32_t i = 0; i < colCount; i++) {
  1.1692 +    CellData* data = cellMap->GetDataAt(aLineNumber, i);
  1.1693 +    if (data && data->IsOrig()) {
  1.1694 +      *aFirstFrameOnLine = (nsIFrame*)data->GetCellFrame();
  1.1695 +      nsIFrame* parent = (*aFirstFrameOnLine)->GetParent();
  1.1696 +      aLineBounds = parent->GetRect();
  1.1697 +      return NS_OK;
  1.1698 +    }
  1.1699 +  }
  1.1700 +  NS_ERROR("cellmap is lying");
  1.1701 +  return NS_ERROR_FAILURE;
  1.1702 +}
  1.1703 +  
  1.1704 +int32_t
  1.1705 +nsTableRowGroupFrame::FindLineContaining(nsIFrame* aFrame, int32_t aStartLine)
  1.1706 +{
  1.1707 +  NS_ENSURE_TRUE(aFrame, -1);
  1.1708 +  
  1.1709 +  nsTableRowFrame *rowFrame = do_QueryFrame(aFrame);
  1.1710 +  NS_ASSERTION(rowFrame, "RowGroup contains a frame that is not a row");
  1.1711 +
  1.1712 +  int32_t rowIndexInGroup = rowFrame->GetRowIndex() - GetStartRowIndex();
  1.1713 +
  1.1714 +  return rowIndexInGroup >= aStartLine ? rowIndexInGroup : -1;
  1.1715 +}
  1.1716 +
  1.1717 +NS_IMETHODIMP
  1.1718 +nsTableRowGroupFrame::CheckLineOrder(int32_t                  aLine,
  1.1719 +                                     bool                     *aIsReordered,
  1.1720 +                                     nsIFrame                 **aFirstVisual,
  1.1721 +                                     nsIFrame                 **aLastVisual)
  1.1722 +{
  1.1723 +  *aIsReordered = false;
  1.1724 +  *aFirstVisual = nullptr;
  1.1725 +  *aLastVisual = nullptr;
  1.1726 +  return NS_OK;
  1.1727 +}
  1.1728 +
  1.1729 +NS_IMETHODIMP
  1.1730 +nsTableRowGroupFrame::FindFrameAt(int32_t    aLineNumber, 
  1.1731 +                                  nscoord    aX, 
  1.1732 +                                  nsIFrame** aFrameFound,
  1.1733 +                                  bool*    aXIsBeforeFirstFrame, 
  1.1734 +                                  bool*    aXIsAfterLastFrame)
  1.1735 +{
  1.1736 +   nsTableFrame* table = nsTableFrame::GetTableFrame(this);
  1.1737 +   nsTableCellMap* cellMap = table->GetCellMap();
  1.1738 +   
  1.1739 +   *aFrameFound = nullptr;
  1.1740 +   *aXIsBeforeFirstFrame = true;
  1.1741 +   *aXIsAfterLastFrame = false;
  1.1742 +
  1.1743 +   aLineNumber += GetStartRowIndex();
  1.1744 +   int32_t numCells = cellMap->GetNumCellsOriginatingInRow(aLineNumber);
  1.1745 +   if (numCells == 0) {
  1.1746 +     return NS_OK;
  1.1747 +   }
  1.1748 +  
  1.1749 +   nsIFrame* frame = nullptr;
  1.1750 +   int32_t colCount = table->GetColCount();
  1.1751 +   for (int32_t i = 0; i < colCount; i++) {
  1.1752 +     CellData* data = cellMap->GetDataAt(aLineNumber, i);
  1.1753 +     if (data && data->IsOrig()) {
  1.1754 +       frame = (nsIFrame*)data->GetCellFrame();
  1.1755 +       break;
  1.1756 +     }
  1.1757 +   }
  1.1758 +   NS_ASSERTION(frame, "cellmap is lying");
  1.1759 +   bool isRTL = (NS_STYLE_DIRECTION_RTL ==
  1.1760 +                   table->StyleVisibility()->mDirection);
  1.1761 +   
  1.1762 +   nsIFrame* closestFromLeft = nullptr;
  1.1763 +   nsIFrame* closestFromRight = nullptr;
  1.1764 +   int32_t n = numCells;
  1.1765 +   nsIFrame* firstFrame = frame;
  1.1766 +   while (n--) {
  1.1767 +     nsRect rect = frame->GetRect();
  1.1768 +     if (rect.width > 0) {
  1.1769 +       // If aX is inside this frame - this is it
  1.1770 +       if (rect.x <= aX && rect.XMost() > aX) {
  1.1771 +         closestFromLeft = closestFromRight = frame;
  1.1772 +         break;
  1.1773 +       }
  1.1774 +       if (rect.x < aX) {
  1.1775 +         if (!closestFromLeft ||
  1.1776 +             rect.XMost() > closestFromLeft->GetRect().XMost())
  1.1777 +           closestFromLeft = frame;
  1.1778 +       }
  1.1779 +       else {
  1.1780 +         if (!closestFromRight ||
  1.1781 +             rect.x < closestFromRight->GetRect().x)
  1.1782 +           closestFromRight = frame;
  1.1783 +       }
  1.1784 +     }
  1.1785 +     frame = frame->GetNextSibling();
  1.1786 +   }
  1.1787 +   if (!closestFromLeft && !closestFromRight) {
  1.1788 +     // All frames were zero-width. Just take the first one.
  1.1789 +     closestFromLeft = closestFromRight = firstFrame;
  1.1790 +   }
  1.1791 +   *aXIsBeforeFirstFrame = isRTL ? !closestFromRight : !closestFromLeft;
  1.1792 +   *aXIsAfterLastFrame =   isRTL ? !closestFromLeft : !closestFromRight;
  1.1793 +   if (closestFromLeft == closestFromRight) {
  1.1794 +     *aFrameFound = closestFromLeft;
  1.1795 +   }
  1.1796 +   else if (!closestFromLeft) {
  1.1797 +     *aFrameFound = closestFromRight;
  1.1798 +   }
  1.1799 +   else if (!closestFromRight) {
  1.1800 +     *aFrameFound = closestFromLeft;
  1.1801 +   }
  1.1802 +   else { // we're between two frames
  1.1803 +     nscoord delta = closestFromRight->GetRect().x -
  1.1804 +                     closestFromLeft->GetRect().XMost();
  1.1805 +     if (aX < closestFromLeft->GetRect().XMost() + delta/2)
  1.1806 +       *aFrameFound = closestFromLeft;
  1.1807 +     else
  1.1808 +       *aFrameFound = closestFromRight;
  1.1809 +  }
  1.1810 +  return NS_OK;
  1.1811 +}
  1.1812 +
  1.1813 +NS_IMETHODIMP
  1.1814 +nsTableRowGroupFrame::GetNextSiblingOnLine(nsIFrame*& aFrame, 
  1.1815 +                                           int32_t    aLineNumber)
  1.1816 +{
  1.1817 +  NS_ENSURE_ARG_POINTER(aFrame);
  1.1818 +  aFrame = aFrame->GetNextSibling();
  1.1819 +  return NS_OK;
  1.1820 +}
  1.1821 +
  1.1822 +//end nsLineIterator methods
  1.1823 +
  1.1824 +static void
  1.1825 +DestroyFrameCursorData(void* aPropertyValue)
  1.1826 +{
  1.1827 +  delete static_cast<nsTableRowGroupFrame::FrameCursorData*>(aPropertyValue);
  1.1828 +}
  1.1829 +
  1.1830 +NS_DECLARE_FRAME_PROPERTY(RowCursorProperty, DestroyFrameCursorData)
  1.1831 +
  1.1832 +void
  1.1833 +nsTableRowGroupFrame::ClearRowCursor()
  1.1834 +{
  1.1835 +  if (!(GetStateBits() & NS_ROWGROUP_HAS_ROW_CURSOR))
  1.1836 +    return;
  1.1837 +
  1.1838 +  RemoveStateBits(NS_ROWGROUP_HAS_ROW_CURSOR);
  1.1839 +  Properties().Delete(RowCursorProperty());
  1.1840 +}
  1.1841 +
  1.1842 +nsTableRowGroupFrame::FrameCursorData*
  1.1843 +nsTableRowGroupFrame::SetupRowCursor()
  1.1844 +{
  1.1845 +  if (GetStateBits() & NS_ROWGROUP_HAS_ROW_CURSOR) {
  1.1846 +    // We already have a valid row cursor. Don't waste time rebuilding it.
  1.1847 +    return nullptr;
  1.1848 +  }
  1.1849 +
  1.1850 +  nsIFrame* f = mFrames.FirstChild();
  1.1851 +  int32_t count;
  1.1852 +  for (count = 0; f && count < MIN_ROWS_NEEDING_CURSOR; ++count) {
  1.1853 +    f = f->GetNextSibling();
  1.1854 +  }
  1.1855 +  if (!f) {
  1.1856 +    // Less than MIN_ROWS_NEEDING_CURSOR rows, so just don't bother
  1.1857 +    return nullptr;
  1.1858 +  }
  1.1859 +
  1.1860 +  FrameCursorData* data = new FrameCursorData();
  1.1861 +  if (!data)
  1.1862 +    return nullptr;
  1.1863 +  Properties().Set(RowCursorProperty(), data);
  1.1864 +  AddStateBits(NS_ROWGROUP_HAS_ROW_CURSOR);
  1.1865 +  return data;
  1.1866 +}
  1.1867 +
  1.1868 +nsIFrame*
  1.1869 +nsTableRowGroupFrame::GetFirstRowContaining(nscoord aY, nscoord* aOverflowAbove)
  1.1870 +{
  1.1871 +  if (!(GetStateBits() & NS_ROWGROUP_HAS_ROW_CURSOR))
  1.1872 +    return nullptr;
  1.1873 +
  1.1874 +  FrameCursorData* property = static_cast<FrameCursorData*>
  1.1875 +    (Properties().Get(RowCursorProperty()));
  1.1876 +  uint32_t cursorIndex = property->mCursorIndex;
  1.1877 +  uint32_t frameCount = property->mFrames.Length();
  1.1878 +  if (cursorIndex >= frameCount)
  1.1879 +    return nullptr;
  1.1880 +  nsIFrame* cursorFrame = property->mFrames[cursorIndex];
  1.1881 +
  1.1882 +  // The cursor's frame list excludes frames with empty overflow-area, so
  1.1883 +  // we don't need to check that here.
  1.1884 +  
  1.1885 +  // We use property->mOverflowBelow here instead of computing the frame's
  1.1886 +  // true overflowArea.YMost(), because it is essential for the thresholds
  1.1887 +  // to form a monotonically increasing sequence. Otherwise we would break
  1.1888 +  // encountering a row whose overflowArea.YMost() is <= aY but which has
  1.1889 +  // a row above it containing cell(s) that span to include aY.
  1.1890 +  while (cursorIndex > 0 &&
  1.1891 +         cursorFrame->GetRect().YMost() + property->mOverflowBelow > aY) {
  1.1892 +    --cursorIndex;
  1.1893 +    cursorFrame = property->mFrames[cursorIndex];
  1.1894 +  }
  1.1895 +  while (cursorIndex + 1 < frameCount &&
  1.1896 +         cursorFrame->GetRect().YMost() + property->mOverflowBelow <= aY) {
  1.1897 +    ++cursorIndex;
  1.1898 +    cursorFrame = property->mFrames[cursorIndex];
  1.1899 +  }
  1.1900 +
  1.1901 +  property->mCursorIndex = cursorIndex;
  1.1902 +  *aOverflowAbove = property->mOverflowAbove;
  1.1903 +  return cursorFrame;
  1.1904 +}
  1.1905 +
  1.1906 +bool
  1.1907 +nsTableRowGroupFrame::FrameCursorData::AppendFrame(nsIFrame* aFrame)
  1.1908 +{
  1.1909 +  nsRect overflowRect = aFrame->GetVisualOverflowRect();
  1.1910 +  if (overflowRect.IsEmpty())
  1.1911 +    return true;
  1.1912 +  nscoord overflowAbove = -overflowRect.y;
  1.1913 +  nscoord overflowBelow = overflowRect.YMost() - aFrame->GetSize().height;
  1.1914 +  mOverflowAbove = std::max(mOverflowAbove, overflowAbove);
  1.1915 +  mOverflowBelow = std::max(mOverflowBelow, overflowBelow);
  1.1916 +  return mFrames.AppendElement(aFrame) != nullptr;
  1.1917 +}
  1.1918 +  
  1.1919 +void 
  1.1920 +nsTableRowGroupFrame::InvalidateFrame(uint32_t aDisplayItemKey)
  1.1921 +{
  1.1922 +  nsIFrame::InvalidateFrame(aDisplayItemKey);
  1.1923 +  GetParent()->InvalidateFrameWithRect(GetVisualOverflowRect() + GetPosition(), aDisplayItemKey);
  1.1924 +}
  1.1925 +
  1.1926 +void 
  1.1927 +nsTableRowGroupFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
  1.1928 +{
  1.1929 +  nsIFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey);
  1.1930 +  // If we have filters applied that would affects our bounds, then
  1.1931 +  // we get an inactive layer created and this is computed
  1.1932 +  // within FrameLayerBuilder
  1.1933 +  GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey);
  1.1934 +}

mercurial