Blame layout/tables/nsTableRowGroupFrame.cpp

Packit f0b94e
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
Packit f0b94e
/* This Source Code Form is subject to the terms of the Mozilla Public
Packit f0b94e
 * License, v. 2.0. If a copy of the MPL was not distributed with this
Packit f0b94e
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Packit f0b94e
#include "nsCOMPtr.h"
Packit f0b94e
#include "nsTableRowGroupFrame.h"
Packit f0b94e
#include "nsTableRowFrame.h"
Packit f0b94e
#include "nsTableFrame.h"
Packit f0b94e
#include "nsTableCellFrame.h"
Packit f0b94e
#include "nsPresContext.h"
Packit f0b94e
#include "nsStyleContext.h"
Packit f0b94e
#include "nsStyleConsts.h"
Packit f0b94e
#include "nsIContent.h"
Packit f0b94e
#include "nsGkAtoms.h"
Packit f0b94e
#include "nsIPresShell.h"
Packit f0b94e
#include "nsCSSRendering.h"
Packit f0b94e
#include "nsHTMLParts.h"
Packit f0b94e
#include "nsCSSFrameConstructor.h"
Packit f0b94e
#include "nsDisplayList.h"
Packit f0b94e
Packit f0b94e
#include "nsCellMap.h"  //table cell navigation
Packit f0b94e
#include <algorithm>
Packit f0b94e
Packit f0b94e
using namespace mozilla;
Packit f0b94e
using namespace mozilla::layout;
Packit f0b94e
Packit f0b94e
namespace mozilla {
Packit f0b94e
Packit f0b94e
struct TableRowGroupReflowInput {
Packit f0b94e
  const ReflowInput& reflowInput;  // Our reflow state
Packit f0b94e
Packit f0b94e
  nsTableFrame* tableFrame;
Packit f0b94e
Packit f0b94e
  // The available size (computed from the parent)
Packit f0b94e
  mozilla::LogicalSize availSize;
Packit f0b94e
Packit f0b94e
  // Running block-offset
Packit f0b94e
  nscoord bCoord;
Packit f0b94e
Packit f0b94e
  TableRowGroupReflowInput(const ReflowInput& aReflowInput,
Packit f0b94e
                           nsTableFrame* aTableFrame)
Packit f0b94e
      : reflowInput(aReflowInput),
Packit f0b94e
        tableFrame(aTableFrame),
Packit f0b94e
        availSize(aReflowInput.GetWritingMode(), aReflowInput.AvailableISize(),
Packit f0b94e
                  aReflowInput.AvailableBSize()),
Packit f0b94e
        bCoord(0) {}
Packit f0b94e
Packit f0b94e
  ~TableRowGroupReflowInput() {}
Packit f0b94e
};
Packit f0b94e
Packit f0b94e
}  // namespace mozilla
Packit f0b94e
Packit f0b94e
nsTableRowGroupFrame::nsTableRowGroupFrame(nsStyleContext* aContext)
Packit f0b94e
    : nsContainerFrame(aContext, kClassID) {
Packit f0b94e
  SetRepeatable(false);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
nsTableRowGroupFrame::~nsTableRowGroupFrame() {}
Packit f0b94e
Packit f0b94e
void nsTableRowGroupFrame::DestroyFrom(nsIFrame* aDestructRoot,
Packit f0b94e
                                       PostDestroyData& aPostDestroyData) {
Packit f0b94e
  if (HasAnyStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)) {
Packit f0b94e
    nsTableFrame::UnregisterPositionedTablePart(this, aDestructRoot);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  nsContainerFrame::DestroyFrom(aDestructRoot, aPostDestroyData);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_QUERYFRAME_HEAD(nsTableRowGroupFrame)
Packit f0b94e
NS_QUERYFRAME_ENTRY(nsTableRowGroupFrame)
Packit f0b94e
NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
Packit f0b94e
Packit f0b94e
int32_t nsTableRowGroupFrame::GetRowCount() {
Packit f0b94e
#ifdef DEBUG
Packit f0b94e
  for (nsFrameList::Enumerator e(mFrames); !e.AtEnd(); e.Next()) {
Packit f0b94e
    NS_ASSERTION(
Packit f0b94e
        e.get()->StyleDisplay()->mDisplay == mozilla::StyleDisplay::TableRow,
Packit f0b94e
        "Unexpected display");
Packit f0b94e
    NS_ASSERTION(e.get()->IsTableRowFrame(), "Unexpected frame type");
Packit f0b94e
  }
Packit f0b94e
#endif
Packit f0b94e
Packit f0b94e
  return mFrames.GetLength();
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
int32_t nsTableRowGroupFrame::GetStartRowIndex() {
Packit f0b94e
  int32_t result = -1;
Packit f0b94e
  if (mFrames.NotEmpty()) {
Packit f0b94e
    NS_ASSERTION(mFrames.FirstChild()->IsTableRowFrame(),
Packit f0b94e
                 "Unexpected frame type");
Packit f0b94e
    result = static_cast<nsTableRowFrame*>(mFrames.FirstChild())->GetRowIndex();
Packit f0b94e
  }
Packit f0b94e
  // if the row group doesn't have any children, get it the hard way
Packit f0b94e
  if (-1 == result) {
Packit f0b94e
    return GetTableFrame()->GetStartRowIndex(this);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return result;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void nsTableRowGroupFrame::AdjustRowIndices(int32_t aRowIndex,
Packit f0b94e
                                            int32_t anAdjustment) {
Packit f0b94e
  for (nsIFrame* rowFrame : mFrames) {
Packit f0b94e
    if (mozilla::StyleDisplay::TableRow == rowFrame->StyleDisplay()->mDisplay) {
Packit f0b94e
      int32_t index = ((nsTableRowFrame*)rowFrame)->GetRowIndex();
Packit f0b94e
      if (index >= aRowIndex)
Packit f0b94e
        ((nsTableRowFrame*)rowFrame)->SetRowIndex(index + anAdjustment);
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
int32_t nsTableRowGroupFrame::GetAdjustmentForStoredIndex(
Packit f0b94e
    int32_t aStoredIndex) {
Packit f0b94e
  nsTableFrame* tableFrame = GetTableFrame();
Packit f0b94e
  return tableFrame->GetAdjustmentForStoredIndex(aStoredIndex);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void nsTableRowGroupFrame::MarkRowsAsDeleted(nsTableRowFrame& aStartRowFrame,
Packit f0b94e
                                             int32_t aNumRowsToDelete) {
Packit f0b94e
  nsTableRowFrame* currentRowFrame = &aStartRowFrame;
Packit f0b94e
  for (;;) {
Packit f0b94e
    // XXXneerja - Instead of calling AddDeletedRowIndex() per row frame
Packit f0b94e
    // it is possible to change AddDeleteRowIndex to instead take
Packit f0b94e
    // <start row index> and <num of rows to mark for deletion> as arguments.
Packit f0b94e
    // The problem that emerges here is mDeletedRowIndexRanges only stores
Packit f0b94e
    // disjoint index ranges and since AddDeletedRowIndex() must operate on
Packit f0b94e
    // the "stored" index, in some cases it is possible that the range
Packit f0b94e
    // of indices to delete becomes overlapping EG: Deleting rows 9 - 11 and
Packit f0b94e
    // then from the remaining rows deleting the *new* rows 7 to 20.
Packit f0b94e
    // Handling these overlapping ranges is much more complicated to
Packit f0b94e
    // implement and so I opted to add the deleted row index of one row at a
Packit f0b94e
    // time and maintain the invariant that the range of deleted row indices
Packit f0b94e
    // is always disjoint.
Packit f0b94e
    currentRowFrame->AddDeletedRowIndex();
Packit f0b94e
    if (--aNumRowsToDelete == 0) {
Packit f0b94e
      break;
Packit f0b94e
    }
Packit f0b94e
    currentRowFrame = do_QueryFrame(currentRowFrame->GetNextSibling());
Packit f0b94e
    if (!currentRowFrame) {
Packit f0b94e
      MOZ_ASSERT_UNREACHABLE("expected another row frame");
Packit f0b94e
      break;
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void nsTableRowGroupFrame::AddDeletedRowIndex(int32_t aDeletedRowStoredIndex) {
Packit f0b94e
  nsTableFrame* tableFrame = GetTableFrame();
Packit f0b94e
  return tableFrame->AddDeletedRowIndex(aDeletedRowStoredIndex);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
nsresult nsTableRowGroupFrame::InitRepeatedFrame(
Packit f0b94e
    nsTableRowGroupFrame* aHeaderFooterFrame) {
Packit f0b94e
  nsTableRowFrame* copyRowFrame = GetFirstRow();
Packit f0b94e
  nsTableRowFrame* originalRowFrame = aHeaderFooterFrame->GetFirstRow();
Packit f0b94e
  AddStateBits(NS_REPEATED_ROW_OR_ROWGROUP);
Packit f0b94e
  while (copyRowFrame && originalRowFrame) {
Packit f0b94e
    copyRowFrame->AddStateBits(NS_REPEATED_ROW_OR_ROWGROUP);
Packit f0b94e
    int rowIndex = originalRowFrame->GetRowIndex();
Packit f0b94e
    copyRowFrame->SetRowIndex(rowIndex);
Packit f0b94e
Packit f0b94e
    // For each table cell frame set its column index
Packit f0b94e
    nsTableCellFrame* originalCellFrame = originalRowFrame->GetFirstCell();
Packit f0b94e
    nsTableCellFrame* copyCellFrame = copyRowFrame->GetFirstCell();
Packit f0b94e
    while (copyCellFrame && originalCellFrame) {
Packit f0b94e
      NS_ASSERTION(
Packit f0b94e
          originalCellFrame->GetContent() == copyCellFrame->GetContent(),
Packit f0b94e
          "cell frames have different content");
Packit f0b94e
      uint32_t colIndex = originalCellFrame->ColIndex();
Packit f0b94e
      copyCellFrame->SetColIndex(colIndex);
Packit f0b94e
Packit f0b94e
      // Move to the next cell frame
Packit f0b94e
      copyCellFrame = copyCellFrame->GetNextCell();
Packit f0b94e
      originalCellFrame = originalCellFrame->GetNextCell();
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    // Move to the next row frame
Packit f0b94e
    originalRowFrame = originalRowFrame->GetNextRow();
Packit f0b94e
    copyRowFrame = copyRowFrame->GetNextRow();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
// Handle the child-traversal part of DisplayGenericTablePart
Packit f0b94e
static void DisplayRows(nsDisplayListBuilder* aBuilder, nsFrame* aFrame,
Packit f0b94e
                        const nsDisplayListSet& aLists) {
Packit f0b94e
  nscoord overflowAbove;
Packit f0b94e
  nsTableRowGroupFrame* f = static_cast<nsTableRowGroupFrame*>(aFrame);
Packit f0b94e
  // Don't try to use the row cursor if we have to descend into placeholders;
Packit f0b94e
  // we might have rows containing placeholders, where the row's overflow
Packit f0b94e
  // area doesn't intersect the dirty rect but we need to descend into the row
Packit f0b94e
  // to see out of flows.
Packit f0b94e
  // Note that we really want to check ShouldDescendIntoFrame for all
Packit f0b94e
  // the rows in |f|, but that's exactly what we're trying to avoid, so we
Packit f0b94e
  // approximate it by checking it for |f|: if it's true for any row
Packit f0b94e
  // in |f| then it's true for |f| itself.
Packit f0b94e
  nsIFrame* kid = aBuilder->ShouldDescendIntoFrame(f, true)
Packit f0b94e
                      ? nullptr
Packit f0b94e
                      : f->GetFirstRowContaining(aBuilder->GetVisibleRect().y,
Packit f0b94e
                                                 &overflowAbove);
Packit f0b94e
Packit f0b94e
  if (kid) {
Packit f0b94e
    // have a cursor, use it
Packit f0b94e
    while (kid) {
Packit f0b94e
      if (kid->GetRect().y - overflowAbove >=
Packit f0b94e
              aBuilder->GetVisibleRect().YMost() &&
Packit f0b94e
          kid->GetNormalRect().y - overflowAbove >=
Packit f0b94e
              aBuilder->GetVisibleRect().YMost())
Packit f0b94e
        break;
Packit f0b94e
      f->BuildDisplayListForChild(aBuilder, kid, aLists);
Packit f0b94e
      kid = kid->GetNextSibling();
Packit f0b94e
    }
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // No cursor. Traverse children the hard way and build a cursor while we're at
Packit f0b94e
  // it
Packit f0b94e
  nsTableRowGroupFrame::FrameCursorData* cursor = f->SetupRowCursor();
Packit f0b94e
  kid = f->PrincipalChildList().FirstChild();
Packit f0b94e
  while (kid) {
Packit f0b94e
    f->BuildDisplayListForChild(aBuilder, kid, aLists);
Packit f0b94e
Packit f0b94e
    if (cursor) {
Packit f0b94e
      if (!cursor->AppendFrame(kid)) {
Packit f0b94e
        f->ClearRowCursor();
Packit f0b94e
        return;
Packit f0b94e
      }
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    kid = kid->GetNextSibling();
Packit f0b94e
  }
Packit f0b94e
  if (cursor) {
Packit f0b94e
    cursor->FinishBuildingCursor();
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void nsTableRowGroupFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
Packit f0b94e
                                            const nsDisplayListSet& aLists) {
Packit f0b94e
  nsTableFrame::DisplayGenericTablePart(aBuilder, this, aLists, DisplayRows);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
nsIFrame::LogicalSides nsTableRowGroupFrame::GetLogicalSkipSides(
Packit f0b94e
    const ReflowInput* aReflowInput) const {
Packit f0b94e
  if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
Packit f0b94e
                   StyleBoxDecorationBreak::Clone)) {
Packit f0b94e
    return LogicalSides();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  LogicalSides skip;
Packit f0b94e
  if (nullptr != GetPrevInFlow()) {
Packit f0b94e
    skip |= eLogicalSideBitsBStart;
Packit f0b94e
  }
Packit f0b94e
  if (nullptr != GetNextInFlow()) {
Packit f0b94e
    skip |= eLogicalSideBitsBEnd;
Packit f0b94e
  }
Packit f0b94e
  return skip;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
// Position and size aKidFrame and update our reflow state.
Packit f0b94e
void nsTableRowGroupFrame::PlaceChild(
Packit f0b94e
    nsPresContext* aPresContext, TableRowGroupReflowInput& aReflowInput,
Packit f0b94e
    nsIFrame* aKidFrame, WritingMode aWM, const LogicalPoint& aKidPosition,
Packit f0b94e
    const nsSize& aContainerSize, ReflowOutput& aDesiredSize,
Packit f0b94e
    const nsRect& aOriginalKidRect, const nsRect& aOriginalKidVisualOverflow) {
Packit f0b94e
  bool isFirstReflow = aKidFrame->HasAnyStateBits(NS_FRAME_FIRST_REFLOW);
Packit f0b94e
Packit f0b94e
  // Place and size the child
Packit f0b94e
  FinishReflowChild(aKidFrame, aPresContext, aDesiredSize, nullptr, aWM,
Packit f0b94e
                    aKidPosition, aContainerSize, 0);
Packit f0b94e
Packit f0b94e
  nsTableFrame* tableFrame = GetTableFrame();
Packit f0b94e
  if (tableFrame->IsBorderCollapse()) {
Packit f0b94e
    nsTableFrame::InvalidateTableFrame(
Packit f0b94e
        aKidFrame, aOriginalKidRect, aOriginalKidVisualOverflow, isFirstReflow);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // Adjust the running block-offset
Packit f0b94e
  aReflowInput.bCoord += aDesiredSize.BSize(aWM);
Packit f0b94e
Packit f0b94e
  // If our block-size is constrained then update the available bsize
Packit f0b94e
  if (NS_UNCONSTRAINEDSIZE != aReflowInput.availSize.BSize(aWM)) {
Packit f0b94e
    aReflowInput.availSize.BSize(aWM) -= aDesiredSize.BSize(aWM);
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void nsTableRowGroupFrame::InitChildReflowInput(nsPresContext& aPresContext,
Packit f0b94e
                                                bool aBorderCollapse,
Packit f0b94e
                                                ReflowInput& aReflowInput) {
Packit f0b94e
  nsMargin collapseBorder;
Packit f0b94e
  nsMargin padding(0, 0, 0, 0);
Packit f0b94e
  nsMargin* pCollapseBorder = nullptr;
Packit f0b94e
  if (aBorderCollapse) {
Packit f0b94e
    nsTableRowFrame* rowFrame = do_QueryFrame(aReflowInput.mFrame);
Packit f0b94e
    if (rowFrame) {
Packit f0b94e
      WritingMode wm = GetWritingMode();
Packit f0b94e
      LogicalMargin border = rowFrame->GetBCBorderWidth(wm);
Packit f0b94e
      collapseBorder = border.GetPhysicalMargin(wm);
Packit f0b94e
      pCollapseBorder = &collapseBorder;
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
  aReflowInput.Init(&aPresContext, nullptr, pCollapseBorder, &padding);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
static void CacheRowBSizesForPrinting(nsPresContext* aPresContext,
Packit f0b94e
                                      nsTableRowFrame* aFirstRow,
Packit f0b94e
                                      WritingMode aWM) {
Packit f0b94e
  for (nsTableRowFrame* row = aFirstRow; row; row = row->GetNextRow()) {
Packit f0b94e
    if (!row->GetPrevInFlow()) {
Packit f0b94e
      row->SetHasUnpaginatedBSize(true);
Packit f0b94e
      row->SetUnpaginatedBSize(aPresContext, row->BSize(aWM));
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void nsTableRowGroupFrame::ReflowChildren(
Packit f0b94e
    nsPresContext* aPresContext, ReflowOutput& aDesiredSize,
Packit f0b94e
    TableRowGroupReflowInput& aReflowInput, nsReflowStatus& aStatus,
Packit f0b94e
    bool* aPageBreakBeforeEnd) {
Packit f0b94e
  if (aPageBreakBeforeEnd) {
Packit f0b94e
    *aPageBreakBeforeEnd = false;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  WritingMode wm = aReflowInput.reflowInput.GetWritingMode();
Packit f0b94e
  nsTableFrame* tableFrame = GetTableFrame();
Packit f0b94e
  const bool borderCollapse = tableFrame->IsBorderCollapse();
Packit f0b94e
Packit f0b94e
  // XXXldb Should we really be checking IsPaginated(),
Packit f0b94e
  // or should we *only* check available block-size?
Packit f0b94e
  // (Think about multi-column layout!)
Packit f0b94e
  bool isPaginated = aPresContext->IsPaginated() &&
Packit f0b94e
                     NS_UNCONSTRAINEDSIZE != aReflowInput.availSize.BSize(wm);
Packit f0b94e
Packit f0b94e
  bool haveRow = false;
Packit f0b94e
  bool reflowAllKids = aReflowInput.reflowInput.ShouldReflowAllKids() ||
Packit f0b94e
                       tableFrame->IsGeometryDirty();
Packit f0b94e
Packit f0b94e
  // in vertical-rl mode, we always need the row bsizes in order to
Packit f0b94e
  // get the necessary containerSize for placing our kids
Packit f0b94e
  bool needToCalcRowBSizes = reflowAllKids || wm.IsVerticalRL();
Packit f0b94e
Packit f0b94e
  nsSize containerSize =
Packit f0b94e
      aReflowInput.reflowInput.ComputedSizeAsContainerIfConstrained();
Packit f0b94e
Packit f0b94e
  nsIFrame* prevKidFrame = nullptr;
Packit f0b94e
  for (nsIFrame *kidFrame = mFrames.FirstChild(); kidFrame;
Packit f0b94e
       prevKidFrame = kidFrame, kidFrame = kidFrame->GetNextSibling()) {
Packit f0b94e
    nsTableRowFrame* rowFrame = do_QueryFrame(kidFrame);
Packit f0b94e
    if (!rowFrame) {
Packit f0b94e
      // XXXldb nsCSSFrameConstructor needs to enforce this!
Packit f0b94e
      NS_NOTREACHED("yikes, a non-row child");
Packit f0b94e
      continue;
Packit f0b94e
    }
Packit f0b94e
    nscoord cellSpacingB = tableFrame->GetRowSpacing(rowFrame->GetRowIndex());
Packit f0b94e
    haveRow = true;
Packit f0b94e
Packit f0b94e
    // Reflow the row frame
Packit f0b94e
    if (reflowAllKids || NS_SUBTREE_DIRTY(kidFrame) ||
Packit f0b94e
        (aReflowInput.reflowInput.mFlags.mSpecialBSizeReflow &&
Packit f0b94e
         (isPaginated ||
Packit f0b94e
          kidFrame->HasAnyStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE)))) {
Packit f0b94e
      LogicalRect oldKidRect = kidFrame->GetLogicalRect(wm, containerSize);
Packit f0b94e
      nsRect oldKidVisualOverflow = kidFrame->GetVisualOverflowRect();
Packit f0b94e
Packit f0b94e
      // XXXldb We used to only pass aDesiredSize.mFlags through for the
Packit f0b94e
      // incremental reflow codepath.
Packit f0b94e
      ReflowOutput desiredSize(aReflowInput.reflowInput, aDesiredSize.mFlags);
Packit f0b94e
      desiredSize.ClearSize();
Packit f0b94e
Packit f0b94e
      // Reflow the child into the available space, giving it as much bsize as
Packit f0b94e
      // it wants. We'll deal with splitting later after we've computed the row
Packit f0b94e
      // bsizes, taking into account cells with row spans...
Packit f0b94e
      LogicalSize kidAvailSize = aReflowInput.availSize;
Packit f0b94e
      kidAvailSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
Packit f0b94e
      ReflowInput kidReflowInput(aPresContext, aReflowInput.reflowInput,
Packit f0b94e
                                 kidFrame, kidAvailSize, nullptr,
Packit f0b94e
                                 ReflowInput::CALLER_WILL_INIT);
Packit f0b94e
      InitChildReflowInput(*aPresContext, borderCollapse, kidReflowInput);
Packit f0b94e
Packit f0b94e
      // This can indicate that columns were resized.
Packit f0b94e
      if (aReflowInput.reflowInput.IsIResize()) {
Packit f0b94e
        kidReflowInput.SetIResize(true);
Packit f0b94e
      }
Packit f0b94e
Packit f0b94e
      NS_ASSERTION(kidFrame == mFrames.FirstChild() || prevKidFrame,
Packit f0b94e
                   "If we're not on the first frame, we should have a "
Packit f0b94e
                   "previous sibling...");
Packit f0b94e
      // If prev row has nonzero YMost, then we can't be at the top of the page
Packit f0b94e
      if (prevKidFrame && prevKidFrame->GetNormalRect().YMost() > 0) {
Packit f0b94e
        kidReflowInput.mFlags.mIsTopOfPage = false;
Packit f0b94e
      }
Packit f0b94e
Packit f0b94e
      LogicalPoint kidPosition(wm, 0, aReflowInput.bCoord);
Packit f0b94e
      ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowInput, wm,
Packit f0b94e
                  kidPosition, containerSize, 0, aStatus);
Packit f0b94e
      kidReflowInput.ApplyRelativePositioning(&kidPosition, containerSize);
Packit f0b94e
Packit f0b94e
      // Place the child
Packit f0b94e
      PlaceChild(aPresContext, aReflowInput, kidFrame, wm, kidPosition,
Packit f0b94e
                 containerSize, desiredSize,
Packit f0b94e
                 oldKidRect.GetPhysicalRect(wm, containerSize),
Packit f0b94e
                 oldKidVisualOverflow);
Packit f0b94e
      aReflowInput.bCoord += cellSpacingB;
Packit f0b94e
Packit f0b94e
      if (!reflowAllKids) {
Packit f0b94e
        if (IsSimpleRowFrame(aReflowInput.tableFrame, rowFrame)) {
Packit f0b94e
          // Inform the row of its new bsize.
Packit f0b94e
          rowFrame->DidResize();
Packit f0b94e
          // the overflow area may have changed inflate the overflow area
Packit f0b94e
          const nsStylePosition* stylePos = StylePosition();
Packit f0b94e
          nsStyleUnit unit = stylePos->BSize(wm).GetUnit();
Packit f0b94e
          if (aReflowInput.tableFrame->IsAutoBSize(wm) &&
Packit f0b94e
              unit != eStyleUnit_Coord) {
Packit f0b94e
            // Because other cells in the row may need to be aligned
Packit f0b94e
            // differently, repaint the entire row
Packit f0b94e
            InvalidateFrame();
Packit f0b94e
          } else if (oldKidRect.BSize(wm) != desiredSize.BSize(wm)) {
Packit f0b94e
            needToCalcRowBSizes = true;
Packit f0b94e
          }
Packit f0b94e
        } else {
Packit f0b94e
          needToCalcRowBSizes = true;
Packit f0b94e
        }
Packit f0b94e
      }
Packit f0b94e
Packit f0b94e
      if (isPaginated && aPageBreakBeforeEnd && !*aPageBreakBeforeEnd) {
Packit f0b94e
        nsTableRowFrame* nextRow = rowFrame->GetNextRow();
Packit f0b94e
        if (nextRow) {
Packit f0b94e
          *aPageBreakBeforeEnd =
Packit f0b94e
              nsTableFrame::PageBreakAfter(kidFrame, nextRow);
Packit f0b94e
        }
Packit f0b94e
      }
Packit f0b94e
    } else {
Packit f0b94e
      SlideChild(aReflowInput, kidFrame);
Packit f0b94e
Packit f0b94e
      // Adjust the running b-offset so we know where the next row should be
Packit f0b94e
      // placed
Packit f0b94e
      nscoord bSize = kidFrame->BSize(wm) + cellSpacingB;
Packit f0b94e
      aReflowInput.bCoord += bSize;
Packit f0b94e
Packit f0b94e
      if (NS_UNCONSTRAINEDSIZE != aReflowInput.availSize.BSize(wm)) {
Packit f0b94e
        aReflowInput.availSize.BSize(wm) -= bSize;
Packit f0b94e
      }
Packit f0b94e
    }
Packit f0b94e
    ConsiderChildOverflow(aDesiredSize.mOverflowAreas, kidFrame);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (haveRow) {
Packit f0b94e
    aReflowInput.bCoord -=
Packit f0b94e
        tableFrame->GetRowSpacing(GetStartRowIndex() + GetRowCount());
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // Return our desired rect
Packit f0b94e
  aDesiredSize.ISize(wm) = aReflowInput.reflowInput.AvailableISize();
Packit f0b94e
  aDesiredSize.BSize(wm) = aReflowInput.bCoord;
Packit f0b94e
Packit f0b94e
  if (aReflowInput.reflowInput.mFlags.mSpecialBSizeReflow) {
Packit f0b94e
    DidResizeRows(aDesiredSize);
Packit f0b94e
    if (isPaginated) {
Packit f0b94e
      CacheRowBSizesForPrinting(aPresContext, GetFirstRow(), wm);
Packit f0b94e
    }
Packit f0b94e
  } else if (needToCalcRowBSizes) {
Packit f0b94e
    CalculateRowBSizes(aPresContext, aDesiredSize, aReflowInput.reflowInput);
Packit f0b94e
    if (!reflowAllKids) {
Packit f0b94e
      InvalidateFrame();
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
nsTableRowFrame* nsTableRowGroupFrame::GetFirstRow() {
Packit f0b94e
  for (nsIFrame* childFrame : mFrames) {
Packit f0b94e
    nsTableRowFrame* rowFrame = do_QueryFrame(childFrame);
Packit f0b94e
    if (rowFrame) {
Packit f0b94e
      return rowFrame;
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
  return nullptr;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
nsTableRowFrame* nsTableRowGroupFrame::GetLastRow() {
Packit f0b94e
  for (auto iter = mFrames.rbegin(), end = mFrames.rend(); iter != end;
Packit f0b94e
       ++iter) {
Packit f0b94e
    nsTableRowFrame* rowFrame = do_QueryFrame(*iter);
Packit f0b94e
    if (rowFrame) {
Packit f0b94e
      return rowFrame;
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
  return nullptr;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
struct RowInfo {
Packit f0b94e
  RowInfo() { bSize = pctBSize = hasStyleBSize = hasPctBSize = isSpecial = 0; }
Packit f0b94e
  unsigned bSize;          // content bsize or fixed bsize, excluding pct bsize
Packit f0b94e
  unsigned pctBSize : 29;  // pct bsize
Packit f0b94e
  unsigned hasStyleBSize : 1;
Packit f0b94e
  unsigned hasPctBSize : 1;
Packit f0b94e
  unsigned isSpecial : 1;  // there is no cell originating in the row with
Packit f0b94e
                           // rowspan=1 and there are at least 2 cells spanning
Packit f0b94e
                           // the row and there is no style bsize on the row
Packit f0b94e
};
Packit f0b94e
Packit f0b94e
static void UpdateBSizes(RowInfo& aRowInfo, nscoord aAdditionalBSize,
Packit f0b94e
                         nscoord& aTotal, nscoord& aUnconstrainedTotal) {
Packit f0b94e
  aRowInfo.bSize += aAdditionalBSize;
Packit f0b94e
  aTotal += aAdditionalBSize;
Packit f0b94e
  if (!aRowInfo.hasStyleBSize) {
Packit f0b94e
    aUnconstrainedTotal += aAdditionalBSize;
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void nsTableRowGroupFrame::DidResizeRows(ReflowOutput& aDesiredSize) {
Packit f0b94e
  // Update the cells spanning rows with their new bsizes.
Packit f0b94e
  // This is the place where all of the cells in the row get set to the bsize
Packit f0b94e
  // of the row.
Packit f0b94e
  // Reset the overflow area.
Packit f0b94e
  aDesiredSize.mOverflowAreas.Clear();
Packit f0b94e
  for (nsTableRowFrame* rowFrame = GetFirstRow(); rowFrame;
Packit f0b94e
       rowFrame = rowFrame->GetNextRow()) {
Packit f0b94e
    rowFrame->DidResize();
Packit f0b94e
    ConsiderChildOverflow(aDesiredSize.mOverflowAreas, rowFrame);
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
// This calculates the bsize of all the rows and takes into account
Packit f0b94e
// style bsize on the row group, style bsizes on rows and cells, style bsizes on
Packit f0b94e
// rowspans. Actual row bsizes will be adjusted later if the table has a style
Packit f0b94e
// bsize. Even if rows don't change bsize, this method must be called to set the
Packit f0b94e
// bsizes of each cell in the row to the bsize of its row.
Packit f0b94e
void nsTableRowGroupFrame::CalculateRowBSizes(nsPresContext* aPresContext,
Packit f0b94e
                                              ReflowOutput& aDesiredSize,
Packit f0b94e
                                              const ReflowInput& aReflowInput) {
Packit f0b94e
  nsTableFrame* tableFrame = GetTableFrame();
Packit f0b94e
  const bool isPaginated = aPresContext->IsPaginated();
Packit f0b94e
Packit f0b94e
  int32_t numEffCols = tableFrame->GetEffectiveColCount();
Packit f0b94e
Packit f0b94e
  int32_t startRowIndex = GetStartRowIndex();
Packit f0b94e
  // find the row corresponding to the row index we just found
Packit f0b94e
  nsTableRowFrame* startRowFrame = GetFirstRow();
Packit f0b94e
Packit f0b94e
  if (!startRowFrame) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // The current row group block-size is the block-origin of the 1st row
Packit f0b94e
  // we are about to calculate a block-size for.
Packit f0b94e
  WritingMode wm = aReflowInput.GetWritingMode();
Packit f0b94e
  nsSize containerSize;  // actual value is unimportant as we're initially
Packit f0b94e
                         // computing sizes, not physical positions
Packit f0b94e
  nscoord startRowGroupBSize =
Packit f0b94e
      startRowFrame->GetLogicalNormalPosition(wm, containerSize).B(wm);
Packit f0b94e
Packit f0b94e
  int32_t numRows =
Packit f0b94e
      GetRowCount() - (startRowFrame->GetRowIndex() - GetStartRowIndex());
Packit f0b94e
  // Collect the current bsize of each row.
Packit f0b94e
  if (numRows <= 0) return;
Packit f0b94e
Packit f0b94e
  AutoTArray<RowInfo, 32> rowInfo;
Packit f0b94e
  if (!rowInfo.AppendElements(numRows)) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  bool hasRowSpanningCell = false;
Packit f0b94e
  nscoord bSizeOfRows = 0;
Packit f0b94e
  nscoord bSizeOfUnStyledRows = 0;
Packit f0b94e
  // Get the bsize of each row without considering rowspans. This will be the
Packit f0b94e
  // max of the largest desired bsize of each cell, the largest style bsize of
Packit f0b94e
  // each cell, the style bsize of the row.
Packit f0b94e
  nscoord pctBSizeBasis = GetBSizeBasis(aReflowInput);
Packit f0b94e
  int32_t
Packit f0b94e
      rowIndex;  // the index in rowInfo, not among the rows in the row group
Packit f0b94e
  nsTableRowFrame* rowFrame;
Packit f0b94e
  for (rowFrame = startRowFrame, rowIndex = 0; rowFrame;
Packit f0b94e
       rowFrame = rowFrame->GetNextRow(), rowIndex++) {
Packit f0b94e
    nscoord nonPctBSize = rowFrame->GetContentBSize();
Packit f0b94e
    if (isPaginated) {
Packit f0b94e
      nonPctBSize = std::max(nonPctBSize, rowFrame->BSize(wm));
Packit f0b94e
    }
Packit f0b94e
    if (!rowFrame->GetPrevInFlow()) {
Packit f0b94e
      if (rowFrame->HasPctBSize()) {
Packit f0b94e
        rowInfo[rowIndex].hasPctBSize = true;
Packit f0b94e
        rowInfo[rowIndex].pctBSize = rowFrame->GetInitialBSize(pctBSizeBasis);
Packit f0b94e
      }
Packit f0b94e
      rowInfo[rowIndex].hasStyleBSize = rowFrame->HasStyleBSize();
Packit f0b94e
      nonPctBSize = std::max(nonPctBSize, rowFrame->GetFixedBSize());
Packit f0b94e
    }
Packit f0b94e
    UpdateBSizes(rowInfo[rowIndex], nonPctBSize, bSizeOfRows,
Packit f0b94e
                 bSizeOfUnStyledRows);
Packit f0b94e
Packit f0b94e
    if (!rowInfo[rowIndex].hasStyleBSize) {
Packit f0b94e
      if (isPaginated ||
Packit f0b94e
          tableFrame->HasMoreThanOneCell(rowIndex + startRowIndex)) {
Packit f0b94e
        rowInfo[rowIndex].isSpecial = true;
Packit f0b94e
        // iteratate the row's cell frames to see if any do not have rowspan > 1
Packit f0b94e
        nsTableCellFrame* cellFrame = rowFrame->GetFirstCell();
Packit f0b94e
        while (cellFrame) {
Packit f0b94e
          int32_t rowSpan = tableFrame->GetEffectiveRowSpan(
Packit f0b94e
              rowIndex + startRowIndex, *cellFrame);
Packit f0b94e
          if (1 == rowSpan) {
Packit f0b94e
            rowInfo[rowIndex].isSpecial = false;
Packit f0b94e
            break;
Packit f0b94e
          }
Packit f0b94e
          cellFrame = cellFrame->GetNextCell();
Packit f0b94e
        }
Packit f0b94e
      }
Packit f0b94e
    }
Packit f0b94e
    // See if a cell spans into the row. If so we'll have to do the next step
Packit f0b94e
    if (!hasRowSpanningCell) {
Packit f0b94e
      if (tableFrame->RowIsSpannedInto(rowIndex + startRowIndex, numEffCols)) {
Packit f0b94e
        hasRowSpanningCell = true;
Packit f0b94e
      }
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (hasRowSpanningCell) {
Packit f0b94e
    // Get the bsize of cells with rowspans and allocate any extra space to the
Packit f0b94e
    // rows they span iteratate the child frames and process the row frames
Packit f0b94e
    // among them
Packit f0b94e
    for (rowFrame = startRowFrame, rowIndex = 0; rowFrame;
Packit f0b94e
         rowFrame = rowFrame->GetNextRow(), rowIndex++) {
Packit f0b94e
      // See if the row has an originating cell with rowspan > 1. We cannot
Packit f0b94e
      // determine this for a row in a continued row group by calling
Packit f0b94e
      // RowHasSpanningCells, because the row's fif may not have any originating
Packit f0b94e
      // cells yet the row may have a continued cell which originates in it.
Packit f0b94e
      if (GetPrevInFlow() || tableFrame->RowHasSpanningCells(
Packit f0b94e
                                 startRowIndex + rowIndex, numEffCols)) {
Packit f0b94e
        nsTableCellFrame* cellFrame = rowFrame->GetFirstCell();
Packit f0b94e
        // iteratate the row's cell frames
Packit f0b94e
        while (cellFrame) {
Packit f0b94e
          nscoord cellSpacingB =
Packit f0b94e
              tableFrame->GetRowSpacing(startRowIndex + rowIndex);
Packit f0b94e
          int32_t rowSpan = tableFrame->GetEffectiveRowSpan(
Packit f0b94e
              rowIndex + startRowIndex, *cellFrame);
Packit f0b94e
          if ((rowIndex + rowSpan) > numRows) {
Packit f0b94e
            // there might be rows pushed already to the nextInFlow
Packit f0b94e
            rowSpan = numRows - rowIndex;
Packit f0b94e
          }
Packit f0b94e
          if (rowSpan > 1) {  // a cell with rowspan > 1, determine the bsize of
Packit f0b94e
                              // the rows it spans
Packit f0b94e
            nscoord bsizeOfRowsSpanned = 0;
Packit f0b94e
            nscoord bsizeOfUnStyledRowsSpanned = 0;
Packit f0b94e
            nscoord numSpecialRowsSpanned = 0;
Packit f0b94e
            nscoord cellSpacingTotal = 0;
Packit f0b94e
            int32_t spanX;
Packit f0b94e
            for (spanX = 0; spanX < rowSpan; spanX++) {
Packit f0b94e
              bsizeOfRowsSpanned += rowInfo[rowIndex + spanX].bSize;
Packit f0b94e
              if (!rowInfo[rowIndex + spanX].hasStyleBSize) {
Packit f0b94e
                bsizeOfUnStyledRowsSpanned += rowInfo[rowIndex + spanX].bSize;
Packit f0b94e
              }
Packit f0b94e
              if (0 != spanX) {
Packit f0b94e
                cellSpacingTotal += cellSpacingB;
Packit f0b94e
              }
Packit f0b94e
              if (rowInfo[rowIndex + spanX].isSpecial) {
Packit f0b94e
                numSpecialRowsSpanned++;
Packit f0b94e
              }
Packit f0b94e
            }
Packit f0b94e
            nscoord bsizeOfAreaSpanned = bsizeOfRowsSpanned + cellSpacingTotal;
Packit f0b94e
            // get the bsize of the cell
Packit f0b94e
            LogicalSize cellFrameSize = cellFrame->GetLogicalSize(wm);
Packit f0b94e
            LogicalSize cellDesSize = cellFrame->GetDesiredSize();
Packit f0b94e
            rowFrame->CalculateCellActualBSize(cellFrame, cellDesSize.BSize(wm),
Packit f0b94e
                                               wm);
Packit f0b94e
            cellFrameSize.BSize(wm) = cellDesSize.BSize(wm);
Packit f0b94e
            if (cellFrame->HasVerticalAlignBaseline()) {
Packit f0b94e
              // to ensure that a spanning cell with a long descender doesn't
Packit f0b94e
              // collide with the next row, we need to take into account the
Packit f0b94e
              // shift that will be done to align the cell on the baseline of
Packit f0b94e
              // the row.
Packit f0b94e
              cellFrameSize.BSize(wm) +=
Packit f0b94e
                  rowFrame->GetMaxCellAscent() - cellFrame->GetCellBaseline();
Packit f0b94e
            }
Packit f0b94e
Packit f0b94e
            if (bsizeOfAreaSpanned < cellFrameSize.BSize(wm)) {
Packit f0b94e
              // the cell's bsize is larger than the available space of the rows
Packit f0b94e
              // it spans so distribute the excess bsize to the rows affected
Packit f0b94e
              nscoord extra = cellFrameSize.BSize(wm) - bsizeOfAreaSpanned;
Packit f0b94e
              nscoord extraUsed = 0;
Packit f0b94e
              if (0 == numSpecialRowsSpanned) {
Packit f0b94e
                // NS_ASSERTION(bsizeOfRowsSpanned > 0, "invalid row span
Packit f0b94e
                // situation");
Packit f0b94e
                bool haveUnStyledRowsSpanned = (bsizeOfUnStyledRowsSpanned > 0);
Packit f0b94e
                nscoord divisor = (haveUnStyledRowsSpanned)
Packit f0b94e
                                      ? bsizeOfUnStyledRowsSpanned
Packit f0b94e
                                      : bsizeOfRowsSpanned;
Packit f0b94e
                if (divisor > 0) {
Packit f0b94e
                  for (spanX = rowSpan - 1; spanX >= 0; spanX--) {
Packit f0b94e
                    if (!haveUnStyledRowsSpanned ||
Packit f0b94e
                        !rowInfo[rowIndex + spanX].hasStyleBSize) {
Packit f0b94e
                      // The amount of additional space each row gets is
Packit f0b94e
                      // proportional to its bsize
Packit f0b94e
                      float percent = ((float)rowInfo[rowIndex + spanX].bSize) /
Packit f0b94e
                                      ((float)divisor);
Packit f0b94e
Packit f0b94e
                      // give rows their percentage, except for the first row
Packit f0b94e
                      // which gets the remainder
Packit f0b94e
                      nscoord extraForRow =
Packit f0b94e
                          (0 == spanX)
Packit f0b94e
                              ? extra - extraUsed
Packit f0b94e
                              : NSToCoordRound(((float)(extra)) * percent);
Packit f0b94e
                      extraForRow = std::min(extraForRow, extra - extraUsed);
Packit f0b94e
                      // update the row bsize
Packit f0b94e
                      UpdateBSizes(rowInfo[rowIndex + spanX], extraForRow,
Packit f0b94e
                                   bSizeOfRows, bSizeOfUnStyledRows);
Packit f0b94e
                      extraUsed += extraForRow;
Packit f0b94e
                      if (extraUsed >= extra) {
Packit f0b94e
                        NS_ASSERTION((extraUsed == extra),
Packit f0b94e
                                     "invalid row bsize calculation");
Packit f0b94e
                        break;
Packit f0b94e
                      }
Packit f0b94e
                    }
Packit f0b94e
                  }
Packit f0b94e
                } else {
Packit f0b94e
                  // put everything in the last row
Packit f0b94e
                  UpdateBSizes(rowInfo[rowIndex + rowSpan - 1], extra,
Packit f0b94e
                               bSizeOfRows, bSizeOfUnStyledRows);
Packit f0b94e
                }
Packit f0b94e
              } else {
Packit f0b94e
                // give the extra to the special rows
Packit f0b94e
                nscoord numSpecialRowsAllocated = 0;
Packit f0b94e
                for (spanX = rowSpan - 1; spanX >= 0; spanX--) {
Packit f0b94e
                  if (rowInfo[rowIndex + spanX].isSpecial) {
Packit f0b94e
                    // The amount of additional space each degenerate row gets
Packit f0b94e
                    // is proportional to the number of them
Packit f0b94e
                    float percent = 1.0f / ((float)numSpecialRowsSpanned);
Packit f0b94e
Packit f0b94e
                    // give rows their percentage, except for the first row
Packit f0b94e
                    // which gets the remainder
Packit f0b94e
                    nscoord extraForRow =
Packit f0b94e
                        (numSpecialRowsSpanned - 1 == numSpecialRowsAllocated)
Packit f0b94e
                            ? extra - extraUsed
Packit f0b94e
                            : NSToCoordRound(((float)(extra)) * percent);
Packit f0b94e
                    extraForRow = std::min(extraForRow, extra - extraUsed);
Packit f0b94e
                    // update the row bsize
Packit f0b94e
                    UpdateBSizes(rowInfo[rowIndex + spanX], extraForRow,
Packit f0b94e
                                 bSizeOfRows, bSizeOfUnStyledRows);
Packit f0b94e
                    extraUsed += extraForRow;
Packit f0b94e
                    if (extraUsed >= extra) {
Packit f0b94e
                      NS_ASSERTION((extraUsed == extra),
Packit f0b94e
                                   "invalid row bsize calculation");
Packit f0b94e
                      break;
Packit f0b94e
                    }
Packit f0b94e
                  }
Packit f0b94e
                }
Packit f0b94e
              }
Packit f0b94e
            }
Packit f0b94e
          }  // if (rowSpan > 1)
Packit f0b94e
          cellFrame = cellFrame->GetNextCell();
Packit f0b94e
        }  // while (cellFrame)
Packit f0b94e
      }    // if (tableFrame->RowHasSpanningCells(startRowIndex + rowIndex) {
Packit f0b94e
    }      // while (rowFrame)
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // pct bsize rows have already got their content bsizes.
Packit f0b94e
  // Give them their pct bsizes up to pctBSizeBasis
Packit f0b94e
  nscoord extra = pctBSizeBasis - bSizeOfRows;
Packit f0b94e
  for (rowFrame = startRowFrame, rowIndex = 0; rowFrame && (extra > 0);
Packit f0b94e
       rowFrame = rowFrame->GetNextRow(), rowIndex++) {
Packit f0b94e
    RowInfo& rInfo = rowInfo[rowIndex];
Packit f0b94e
    if (rInfo.hasPctBSize) {
Packit f0b94e
      nscoord rowExtra =
Packit f0b94e
          (rInfo.pctBSize > rInfo.bSize) ? rInfo.pctBSize - rInfo.bSize : 0;
Packit f0b94e
      rowExtra = std::min(rowExtra, extra);
Packit f0b94e
      UpdateBSizes(rInfo, rowExtra, bSizeOfRows, bSizeOfUnStyledRows);
Packit f0b94e
      extra -= rowExtra;
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  bool styleBSizeAllocation = false;
Packit f0b94e
  nscoord rowGroupBSize = startRowGroupBSize + bSizeOfRows +
Packit f0b94e
                          tableFrame->GetRowSpacing(0, numRows - 1);
Packit f0b94e
  // if we have a style bsize, allocate the extra bsize to unconstrained rows
Packit f0b94e
  if ((aReflowInput.ComputedBSize() > rowGroupBSize) &&
Packit f0b94e
      (NS_UNCONSTRAINEDSIZE != aReflowInput.ComputedBSize())) {
Packit f0b94e
    nscoord extraComputedBSize = aReflowInput.ComputedBSize() - rowGroupBSize;
Packit f0b94e
    nscoord extraUsed = 0;
Packit f0b94e
    bool haveUnStyledRows = (bSizeOfUnStyledRows > 0);
Packit f0b94e
    nscoord divisor = (haveUnStyledRows) ? bSizeOfUnStyledRows : bSizeOfRows;
Packit f0b94e
    if (divisor > 0) {
Packit f0b94e
      styleBSizeAllocation = true;
Packit f0b94e
      for (rowIndex = 0; rowIndex < numRows; rowIndex++) {
Packit f0b94e
        if (!haveUnStyledRows || !rowInfo[rowIndex].hasStyleBSize) {
Packit f0b94e
          // The amount of additional space each row gets is based on the
Packit f0b94e
          // percentage of space it occupies
Packit f0b94e
          float percent = ((float)rowInfo[rowIndex].bSize) / ((float)divisor);
Packit f0b94e
          // give rows their percentage, except for the last row which gets the
Packit f0b94e
          // remainder
Packit f0b94e
          nscoord extraForRow =
Packit f0b94e
              (numRows - 1 == rowIndex)
Packit f0b94e
                  ? extraComputedBSize - extraUsed
Packit f0b94e
                  : NSToCoordRound(((float)extraComputedBSize) * percent);
Packit f0b94e
          extraForRow = std::min(extraForRow, extraComputedBSize - extraUsed);
Packit f0b94e
          // update the row bsize
Packit f0b94e
          UpdateBSizes(rowInfo[rowIndex], extraForRow, bSizeOfRows,
Packit f0b94e
                       bSizeOfUnStyledRows);
Packit f0b94e
          extraUsed += extraForRow;
Packit f0b94e
          if (extraUsed >= extraComputedBSize) {
Packit f0b94e
            NS_ASSERTION((extraUsed == extraComputedBSize),
Packit f0b94e
                         "invalid row bsize calculation");
Packit f0b94e
            break;
Packit f0b94e
          }
Packit f0b94e
        }
Packit f0b94e
      }
Packit f0b94e
    }
Packit f0b94e
    rowGroupBSize = aReflowInput.ComputedBSize();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (wm.IsVertical()) {
Packit f0b94e
    // we need the correct containerSize below for block positioning in
Packit f0b94e
    // vertical-rl writing mode
Packit f0b94e
    containerSize.width = rowGroupBSize;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  nscoord bOrigin = startRowGroupBSize;
Packit f0b94e
  // update the rows with their (potentially) new bsizes
Packit f0b94e
  for (rowFrame = startRowFrame, rowIndex = 0; rowFrame;
Packit f0b94e
       rowFrame = rowFrame->GetNextRow(), rowIndex++) {
Packit f0b94e
    nsRect rowBounds = rowFrame->GetRect();
Packit f0b94e
    LogicalSize rowBoundsSize(wm, rowBounds.Size());
Packit f0b94e
    nsRect rowVisualOverflow = rowFrame->GetVisualOverflowRect();
Packit f0b94e
    nscoord deltaB =
Packit f0b94e
        bOrigin - rowFrame->GetLogicalNormalPosition(wm, containerSize).B(wm);
Packit f0b94e
Packit f0b94e
    nscoord rowBSize =
Packit f0b94e
        (rowInfo[rowIndex].bSize > 0) ? rowInfo[rowIndex].bSize : 0;
Packit f0b94e
Packit f0b94e
    if (deltaB != 0 || (rowBSize != rowBoundsSize.BSize(wm))) {
Packit f0b94e
      // Resize/move the row to its final size and position
Packit f0b94e
      if (deltaB != 0) {
Packit f0b94e
        rowFrame->InvalidateFrameSubtree();
Packit f0b94e
      }
Packit f0b94e
Packit f0b94e
      rowFrame->MovePositionBy(wm, LogicalPoint(wm, 0, deltaB));
Packit f0b94e
      rowFrame->SetSize(LogicalSize(wm, rowBoundsSize.ISize(wm), rowBSize));
Packit f0b94e
Packit f0b94e
      nsTableFrame::InvalidateTableFrame(rowFrame, rowBounds, rowVisualOverflow,
Packit f0b94e
                                         false);
Packit f0b94e
Packit f0b94e
      if (deltaB != 0) {
Packit f0b94e
        nsTableFrame::RePositionViews(rowFrame);
Packit f0b94e
        // XXXbz we don't need to update our overflow area?
Packit f0b94e
      }
Packit f0b94e
    }
Packit f0b94e
    bOrigin += rowBSize + tableFrame->GetRowSpacing(startRowIndex + rowIndex);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (isPaginated && styleBSizeAllocation) {
Packit f0b94e
    // since the row group has a style bsize, cache the row bsizes,
Packit f0b94e
    // so next in flows can honor them
Packit f0b94e
    CacheRowBSizesForPrinting(aPresContext, GetFirstRow(), wm);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  DidResizeRows(aDesiredSize);
Packit f0b94e
Packit f0b94e
  aDesiredSize.BSize(wm) = rowGroupBSize;  // Adjust our desired size
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
nscoord nsTableRowGroupFrame::CollapseRowGroupIfNecessary(nscoord aBTotalOffset,
Packit f0b94e
                                                          nscoord aISize,
Packit f0b94e
                                                          WritingMode aWM) {
Packit f0b94e
  nsTableFrame* tableFrame = GetTableFrame();
Packit f0b94e
  nsSize containerSize = tableFrame->GetSize();
Packit f0b94e
  const nsStyleVisibility* groupVis = StyleVisibility();
Packit f0b94e
  bool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE == groupVis->mVisible);
Packit f0b94e
  if (collapseGroup) {
Packit f0b94e
    tableFrame->SetNeedToCollapse(true);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  nsOverflowAreas overflow;
Packit f0b94e
Packit f0b94e
  nsTableRowFrame* rowFrame = GetFirstRow();
Packit f0b94e
  bool didCollapse = false;
Packit f0b94e
  nscoord bGroupOffset = 0;
Packit f0b94e
  while (rowFrame) {
Packit f0b94e
    bGroupOffset += rowFrame->CollapseRowIfNecessary(
Packit f0b94e
        bGroupOffset, aISize, collapseGroup, didCollapse);
Packit f0b94e
    ConsiderChildOverflow(overflow, rowFrame);
Packit f0b94e
    rowFrame = rowFrame->GetNextRow();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  LogicalRect groupRect = GetLogicalRect(aWM, containerSize);
Packit f0b94e
  nsRect oldGroupRect = GetRect();
Packit f0b94e
  nsRect oldGroupVisualOverflow = GetVisualOverflowRect();
Packit f0b94e
Packit f0b94e
  groupRect.BSize(aWM) -= bGroupOffset;
Packit f0b94e
  if (didCollapse) {
Packit f0b94e
    // add back the cellspacing between rowgroups
Packit f0b94e
    groupRect.BSize(aWM) +=
Packit f0b94e
        tableFrame->GetRowSpacing(GetStartRowIndex() + GetRowCount());
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  groupRect.BStart(aWM) -= aBTotalOffset;
Packit f0b94e
  groupRect.ISize(aWM) = aISize;
Packit f0b94e
Packit f0b94e
  if (aBTotalOffset != 0) {
Packit f0b94e
    InvalidateFrameSubtree();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  SetRect(aWM, groupRect, containerSize);
Packit f0b94e
  overflow.UnionAllWith(
Packit f0b94e
      nsRect(0, 0, groupRect.Width(aWM), groupRect.Height(aWM)));
Packit f0b94e
  FinishAndStoreOverflow(overflow, groupRect.Size(aWM).GetPhysicalSize(aWM));
Packit f0b94e
  nsTableFrame::RePositionViews(this);
Packit f0b94e
  nsTableFrame::InvalidateTableFrame(this, oldGroupRect, oldGroupVisualOverflow,
Packit f0b94e
                                     false);
Packit f0b94e
Packit f0b94e
  return bGroupOffset;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
// Move a child that was skipped during a reflow.
Packit f0b94e
void nsTableRowGroupFrame::SlideChild(TableRowGroupReflowInput& aReflowInput,
Packit f0b94e
                                      nsIFrame* aKidFrame) {
Packit f0b94e
  // Move the frame if we need to.
Packit f0b94e
  WritingMode wm = aReflowInput.reflowInput.GetWritingMode();
Packit f0b94e
  const nsSize containerSize =
Packit f0b94e
      aReflowInput.reflowInput.ComputedSizeAsContainerIfConstrained();
Packit f0b94e
  LogicalPoint oldPosition =
Packit f0b94e
      aKidFrame->GetLogicalNormalPosition(wm, containerSize);
Packit f0b94e
  LogicalPoint newPosition = oldPosition;
Packit f0b94e
  newPosition.B(wm) = aReflowInput.bCoord;
Packit f0b94e
  if (oldPosition.B(wm) != newPosition.B(wm)) {
Packit f0b94e
    aKidFrame->InvalidateFrameSubtree();
Packit f0b94e
    aReflowInput.reflowInput.ApplyRelativePositioning(&newPosition,
Packit f0b94e
                                                      containerSize);
Packit f0b94e
    aKidFrame->SetPosition(wm, newPosition, containerSize);
Packit f0b94e
    nsTableFrame::RePositionViews(aKidFrame);
Packit f0b94e
    aKidFrame->InvalidateFrameSubtree();
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
// Create a continuing frame, add it to the child list, and then push it
Packit f0b94e
// and the frames that follow
Packit f0b94e
void nsTableRowGroupFrame::CreateContinuingRowFrame(nsPresContext& aPresContext,
Packit f0b94e
                                                    nsIFrame& aRowFrame,
Packit f0b94e
                                                    nsIFrame** aContRowFrame) {
Packit f0b94e
  // XXX what is the row index?
Packit f0b94e
  if (!aContRowFrame) {
Packit f0b94e
    NS_ASSERTION(false, "bad call");
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
  // create the continuing frame which will create continuing cell frames
Packit f0b94e
  *aContRowFrame =
Packit f0b94e
      aPresContext.PresShell()->FrameConstructor()->CreateContinuingFrame(
Packit f0b94e
          &aPresContext, &aRowFrame, this);
Packit f0b94e
Packit f0b94e
  // Add the continuing row frame to the child list
Packit f0b94e
  mFrames.InsertFrame(nullptr, &aRowFrame, *aContRowFrame);
Packit f0b94e
Packit f0b94e
  // Push the continuing row frame and the frames that follow
Packit f0b94e
  PushChildren(*aContRowFrame, &aRowFrame);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
// Reflow the cells with rowspan > 1 which originate between aFirstRow
Packit f0b94e
// and end on or after aLastRow. aFirstTruncatedRow is the highest row on the
Packit f0b94e
// page that contains a cell which cannot split on this page
Packit f0b94e
void nsTableRowGroupFrame::SplitSpanningCells(
Packit f0b94e
    nsPresContext& aPresContext, const ReflowInput& aReflowInput,
Packit f0b94e
    nsTableFrame& aTable, nsTableRowFrame& aFirstRow, nsTableRowFrame& aLastRow,
Packit f0b94e
    bool aFirstRowIsTopOfPage, nscoord aSpanningRowBEnd,
Packit f0b94e
    nsTableRowFrame*& aContRow, nsTableRowFrame*& aFirstTruncatedRow,
Packit f0b94e
    nscoord& aDesiredBSize) {
Packit f0b94e
  NS_ASSERTION(aSpanningRowBEnd >= 0, "Can't split negative bsizes");
Packit f0b94e
  aFirstTruncatedRow = nullptr;
Packit f0b94e
  aDesiredBSize = 0;
Packit f0b94e
Packit f0b94e
  const bool borderCollapse = aTable.IsBorderCollapse();
Packit f0b94e
  int32_t lastRowIndex = aLastRow.GetRowIndex();
Packit f0b94e
  bool wasLast = false;
Packit f0b94e
  bool haveRowSpan = false;
Packit f0b94e
  // Iterate the rows between aFirstRow and aLastRow
Packit f0b94e
  for (nsTableRowFrame* row = &aFirstRow; !wasLast; row = row->GetNextRow()) {
Packit f0b94e
    wasLast = (row == &aLastRow);
Packit f0b94e
    int32_t rowIndex = row->GetRowIndex();
Packit f0b94e
    nsPoint rowPos = row->GetNormalPosition();
Packit f0b94e
    // Iterate the cells looking for those that have rowspan > 1
Packit f0b94e
    for (nsTableCellFrame* cell = row->GetFirstCell(); cell;
Packit f0b94e
         cell = cell->GetNextCell()) {
Packit f0b94e
      int32_t rowSpan = aTable.GetEffectiveRowSpan(rowIndex, *cell);
Packit f0b94e
      // Only reflow rowspan > 1 cells which span aLastRow. Those which don't
Packit f0b94e
      // span aLastRow were reflowed correctly during the unconstrained bsize
Packit f0b94e
      // reflow.
Packit f0b94e
      if ((rowSpan > 1) && (rowIndex + rowSpan > lastRowIndex)) {
Packit f0b94e
        haveRowSpan = true;
Packit f0b94e
        nsReflowStatus status;
Packit f0b94e
        // Ask the row to reflow the cell to the bsize of all the rows it spans
Packit f0b94e
        // up through aLastRow cellAvailBSize is the space between the row group
Packit f0b94e
        // start and the end of the page
Packit f0b94e
        nscoord cellAvailBSize = aSpanningRowBEnd - rowPos.y;
Packit f0b94e
        NS_ASSERTION(cellAvailBSize >= 0, "No space for cell?");
Packit f0b94e
        bool isTopOfPage = (row == &aFirstRow) && aFirstRowIsTopOfPage;
Packit f0b94e
Packit f0b94e
        nsRect rowRect = row->GetNormalRect();
Packit f0b94e
        nsSize rowAvailSize(
Packit f0b94e
            aReflowInput.AvailableWidth(),
Packit f0b94e
            std::max(aReflowInput.AvailableHeight() - rowRect.y, 0));
Packit f0b94e
        // don't let the available height exceed what
Packit f0b94e
        // CalculateRowBSizes set for it
Packit f0b94e
        rowAvailSize.height = std::min(rowAvailSize.height, rowRect.height);
Packit f0b94e
        ReflowInput rowReflowInput(
Packit f0b94e
            &aPresContext, aReflowInput, row,
Packit f0b94e
            LogicalSize(row->GetWritingMode(), rowAvailSize), nullptr,
Packit f0b94e
            ReflowInput::CALLER_WILL_INIT);
Packit f0b94e
        InitChildReflowInput(aPresContext, borderCollapse, rowReflowInput);
Packit f0b94e
        rowReflowInput.mFlags.mIsTopOfPage = isTopOfPage;  // set top of page
Packit f0b94e
Packit f0b94e
        nscoord cellBSize =
Packit f0b94e
            row->ReflowCellFrame(&aPresContext, rowReflowInput, isTopOfPage,
Packit f0b94e
                                 cell, cellAvailBSize, status);
Packit f0b94e
        aDesiredBSize = std::max(aDesiredBSize, rowPos.y + cellBSize);
Packit f0b94e
        if (status.IsComplete()) {
Packit f0b94e
          if (cellBSize > cellAvailBSize) {
Packit f0b94e
            aFirstTruncatedRow = row;
Packit f0b94e
            if ((row != &aFirstRow) || !aFirstRowIsTopOfPage) {
Packit f0b94e
              // return now, since we will be getting another reflow after
Packit f0b94e
              // either (1) row is moved to the next page or (2) the row group
Packit f0b94e
              // is moved to the next page
Packit f0b94e
              return;
Packit f0b94e
            }
Packit f0b94e
          }
Packit f0b94e
        } else {
Packit f0b94e
          if (!aContRow) {
Packit f0b94e
            CreateContinuingRowFrame(aPresContext, aLastRow,
Packit f0b94e
                                     (nsIFrame**)&aContRow);
Packit f0b94e
          }
Packit f0b94e
          if (aContRow) {
Packit f0b94e
            if (row != &aLastRow) {
Packit f0b94e
              // aContRow needs a continuation for cell, since cell spanned into
Packit f0b94e
              // aLastRow but does not originate there
Packit f0b94e
              nsTableCellFrame* contCell = static_cast<nsTableCellFrame*>(
Packit f0b94e
                  aPresContext.PresShell()
Packit f0b94e
                      ->FrameConstructor()
Packit f0b94e
                      ->CreateContinuingFrame(&aPresContext, cell, &aLastRow));
Packit f0b94e
              uint32_t colIndex = cell->ColIndex();
Packit f0b94e
              aContRow->InsertCellFrame(contCell, colIndex);
Packit f0b94e
            }
Packit f0b94e
          }
Packit f0b94e
        }
Packit f0b94e
      }
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
  if (!haveRowSpan) {
Packit f0b94e
    aDesiredBSize = aLastRow.GetNormalRect().YMost();
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
// Remove the next-in-flow of the row, its cells and their cell blocks. This
Packit f0b94e
// is necessary in case the row doesn't need a continuation later on or needs
Packit f0b94e
// a continuation which doesn't have the same number of cells that now exist.
Packit f0b94e
void nsTableRowGroupFrame::UndoContinuedRow(nsPresContext* aPresContext,
Packit f0b94e
                                            nsTableRowFrame* aRow) {
Packit f0b94e
  if (!aRow) return;  // allow null aRow to avoid callers doing null checks
Packit f0b94e
Packit f0b94e
  // rowBefore was the prev-sibling of aRow's next-sibling before aRow was
Packit f0b94e
  // created
Packit f0b94e
  nsTableRowFrame* rowBefore = (nsTableRowFrame*)aRow->GetPrevInFlow();
Packit f0b94e
  NS_PRECONDITION(mFrames.ContainsFrame(rowBefore),
Packit f0b94e
                  "rowBefore not in our frame list?");
Packit f0b94e
Packit f0b94e
  AutoFrameListPtr overflows(aPresContext, StealOverflowFrames());
Packit f0b94e
  if (!rowBefore || !overflows || overflows->IsEmpty() ||
Packit f0b94e
      overflows->FirstChild() != aRow) {
Packit f0b94e
    NS_ERROR("invalid continued row");
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // Destroy aRow, its cells, and their cell blocks. Cell blocks that have split
Packit f0b94e
  // will not have reflowed yet to pick up content from any overflow lines.
Packit f0b94e
  overflows->DestroyFrame(aRow);
Packit f0b94e
Packit f0b94e
  // Put the overflow rows into our child list
Packit f0b94e
  if (!overflows->IsEmpty()) {
Packit f0b94e
    mFrames.InsertFrames(nullptr, rowBefore, *overflows);
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
static nsTableRowFrame* GetRowBefore(nsTableRowFrame& aStartRow,
Packit f0b94e
                                     nsTableRowFrame& aRow) {
Packit f0b94e
  nsTableRowFrame* rowBefore = nullptr;
Packit f0b94e
  for (nsTableRowFrame* sib = &aStartRow; sib && (sib != &aRow);
Packit f0b94e
       sib = sib->GetNextRow()) {
Packit f0b94e
    rowBefore = sib;
Packit f0b94e
  }
Packit f0b94e
  return rowBefore;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
nsresult nsTableRowGroupFrame::SplitRowGroup(nsPresContext* aPresContext,
Packit f0b94e
                                             ReflowOutput& aDesiredSize,
Packit f0b94e
                                             const ReflowInput& aReflowInput,
Packit f0b94e
                                             nsTableFrame* aTableFrame,
Packit f0b94e
                                             nsReflowStatus& aStatus,
Packit f0b94e
                                             bool aRowForcedPageBreak) {
Packit f0b94e
  NS_PRECONDITION(aPresContext->IsPaginated(),
Packit f0b94e
                  "SplitRowGroup currently supports only paged media");
Packit f0b94e
Packit f0b94e
  nsTableRowFrame* prevRowFrame = nullptr;
Packit f0b94e
  aDesiredSize.Height() = 0;
Packit f0b94e
Packit f0b94e
  nscoord availWidth = aReflowInput.AvailableWidth();
Packit f0b94e
  nscoord availHeight = aReflowInput.AvailableHeight();
Packit f0b94e
Packit f0b94e
  const bool borderCollapse = aTableFrame->IsBorderCollapse();
Packit f0b94e
Packit f0b94e
  // get the page height
Packit f0b94e
  nscoord pageHeight = aPresContext->GetPageSize().height;
Packit f0b94e
  NS_ASSERTION(pageHeight != NS_UNCONSTRAINEDSIZE,
Packit f0b94e
               "The table shouldn't be split when there should be space");
Packit f0b94e
Packit f0b94e
  bool isTopOfPage = aReflowInput.mFlags.mIsTopOfPage;
Packit f0b94e
  nsTableRowFrame* firstRowThisPage = GetFirstRow();
Packit f0b94e
Packit f0b94e
  // Need to dirty the table's geometry, or else the row might skip
Packit f0b94e
  // reflowing its cell as an optimization.
Packit f0b94e
  aTableFrame->SetGeometryDirty();
Packit f0b94e
Packit f0b94e
  // Walk each of the row frames looking for the first row frame that doesn't
Packit f0b94e
  // fit in the available space
Packit f0b94e
  for (nsTableRowFrame* rowFrame = firstRowThisPage; rowFrame;
Packit f0b94e
       rowFrame = rowFrame->GetNextRow()) {
Packit f0b94e
    bool rowIsOnPage = true;
Packit f0b94e
    nscoord cellSpacingB = aTableFrame->GetRowSpacing(rowFrame->GetRowIndex());
Packit f0b94e
    nsRect rowRect = rowFrame->GetNormalRect();
Packit f0b94e
    // See if the row fits on this page
Packit f0b94e
    if (rowRect.YMost() > availHeight) {
Packit f0b94e
      nsTableRowFrame* contRow = nullptr;
Packit f0b94e
      // Reflow the row in the availabe space and have it split if it is the 1st
Packit f0b94e
      // row (on the page) or there is at least 5% of the current page available
Packit f0b94e
      // XXX this 5% should be made a preference
Packit f0b94e
      if (!prevRowFrame ||
Packit f0b94e
          (availHeight - aDesiredSize.Height() > pageHeight / 20)) {
Packit f0b94e
        nsSize availSize(availWidth, std::max(availHeight - rowRect.y, 0));
Packit f0b94e
        // don't let the available height exceed what CalculateRowHeights set
Packit f0b94e
        // for it
Packit f0b94e
        availSize.height = std::min(availSize.height, rowRect.height);
Packit f0b94e
Packit f0b94e
        ReflowInput rowReflowInput(
Packit f0b94e
            aPresContext, aReflowInput, rowFrame,
Packit f0b94e
            LogicalSize(rowFrame->GetWritingMode(), availSize), nullptr,
Packit f0b94e
            ReflowInput::CALLER_WILL_INIT);
Packit f0b94e
Packit f0b94e
        InitChildReflowInput(*aPresContext, borderCollapse, rowReflowInput);
Packit f0b94e
        rowReflowInput.mFlags.mIsTopOfPage = isTopOfPage;  // set top of page
Packit f0b94e
        ReflowOutput rowMetrics(aReflowInput);
Packit f0b94e
Packit f0b94e
        // Get the old size before we reflow.
Packit f0b94e
        nsRect oldRowRect = rowFrame->GetRect();
Packit f0b94e
        nsRect oldRowVisualOverflow = rowFrame->GetVisualOverflowRect();
Packit f0b94e
Packit f0b94e
        // Reflow the cell with the constrained height. A cell with rowspan >1
Packit f0b94e
        // will get this reflow later during SplitSpanningCells.
Packit f0b94e
        ReflowChild(rowFrame, aPresContext, rowMetrics, rowReflowInput, 0, 0,
Packit f0b94e
                    NS_FRAME_NO_MOVE_FRAME, aStatus);
Packit f0b94e
        rowFrame->SetSize(nsSize(rowMetrics.Width(), rowMetrics.Height()));
Packit f0b94e
        rowFrame->DidReflow(aPresContext, nullptr);
Packit f0b94e
        rowFrame->DidResize();
Packit f0b94e
Packit f0b94e
        if (!aRowForcedPageBreak && !aStatus.IsFullyComplete() &&
Packit f0b94e
            ShouldAvoidBreakInside(aReflowInput)) {
Packit f0b94e
          aStatus.SetInlineLineBreakBeforeAndReset();
Packit f0b94e
          break;
Packit f0b94e
        }
Packit f0b94e
Packit f0b94e
        nsTableFrame::InvalidateTableFrame(rowFrame, oldRowRect,
Packit f0b94e
                                           oldRowVisualOverflow, false);
Packit f0b94e
Packit f0b94e
        if (aStatus.IsIncomplete()) {
Packit f0b94e
          // The row frame is incomplete and all of the rowspan 1 cells' block
Packit f0b94e
          // frames split
Packit f0b94e
          if ((rowMetrics.Height() <= rowReflowInput.AvailableHeight()) ||
Packit f0b94e
              isTopOfPage) {
Packit f0b94e
            // The row stays on this page because either it split ok or we're on
Packit f0b94e
            // the top of page. If top of page and the height exceeded the avail
Packit f0b94e
            // height, then there will be data loss
Packit f0b94e
            NS_ASSERTION(
Packit f0b94e
                rowMetrics.Height() <= rowReflowInput.AvailableHeight(),
Packit f0b94e
                "data loss - incomplete row needed more height than available, "
Packit f0b94e
                "on top of page");
Packit f0b94e
            CreateContinuingRowFrame(*aPresContext, *rowFrame,
Packit f0b94e
                                     (nsIFrame**)&contRow);
Packit f0b94e
            if (contRow) {
Packit f0b94e
              aDesiredSize.Height() += rowMetrics.Height();
Packit f0b94e
              if (prevRowFrame) aDesiredSize.Height() += cellSpacingB;
Packit f0b94e
            } else
Packit f0b94e
              return NS_ERROR_NULL_POINTER;
Packit f0b94e
          } else {
Packit f0b94e
            // Put the row on the next page to give it more height
Packit f0b94e
            rowIsOnPage = false;
Packit f0b94e
          }
Packit f0b94e
        } else {
Packit f0b94e
          // The row frame is complete because either (1) its minimum height is
Packit f0b94e
          // greater than the available height we gave it, or (2) it may have
Packit f0b94e
          // been given a larger height through style than its content, or (3)
Packit f0b94e
          // it contains a rowspan >1 cell which hasn't been reflowed with a
Packit f0b94e
          // constrained height yet (we will find out when SplitSpanningCells is
Packit f0b94e
          // called below)
Packit f0b94e
          if (rowMetrics.Height() > availSize.height ||
Packit f0b94e
              (aStatus.IsInlineBreakBefore() && !aRowForcedPageBreak)) {
Packit f0b94e
            // cases (1) and (2)
Packit f0b94e
            if (isTopOfPage) {
Packit f0b94e
              // We're on top of the page, so keep the row on this page. There
Packit f0b94e
              // will be data loss. Push the row frame that follows
Packit f0b94e
              nsTableRowFrame* nextRowFrame = rowFrame->GetNextRow();
Packit f0b94e
              if (nextRowFrame) {
Packit f0b94e
                aStatus.Reset();
Packit f0b94e
                aStatus.SetIncomplete();
Packit f0b94e
              }
Packit f0b94e
              aDesiredSize.Height() += rowMetrics.Height();
Packit f0b94e
              if (prevRowFrame) aDesiredSize.Height() += cellSpacingB;
Packit f0b94e
              NS_WARNING(
Packit f0b94e
                  "data loss - complete row needed more height than available, "
Packit f0b94e
                  "on top of page");
Packit f0b94e
            } else {
Packit f0b94e
              // We're not on top of the page, so put the row on the next page
Packit f0b94e
              // to give it more height
Packit f0b94e
              rowIsOnPage = false;
Packit f0b94e
            }
Packit f0b94e
          }
Packit f0b94e
        }
Packit f0b94e
      }  // if (!prevRowFrame || (availHeight - aDesiredSize.Height() >
Packit f0b94e
         // pageHeight / 20))
Packit f0b94e
      else {
Packit f0b94e
        // put the row on the next page to give it more height
Packit f0b94e
        rowIsOnPage = false;
Packit f0b94e
      }
Packit f0b94e
Packit f0b94e
      nsTableRowFrame* lastRowThisPage = rowFrame;
Packit f0b94e
      nscoord spanningRowBottom = availHeight;
Packit f0b94e
      if (!rowIsOnPage) {
Packit f0b94e
        NS_ASSERTION(!contRow,
Packit f0b94e
                     "We should not have created a continuation if none of "
Packit f0b94e
                     "this row fits");
Packit f0b94e
        if (!aRowForcedPageBreak && ShouldAvoidBreakInside(aReflowInput)) {
Packit f0b94e
          aStatus.SetInlineLineBreakBeforeAndReset();
Packit f0b94e
          break;
Packit f0b94e
        }
Packit f0b94e
        if (prevRowFrame) {
Packit f0b94e
          spanningRowBottom = prevRowFrame->GetNormalRect().YMost();
Packit f0b94e
          lastRowThisPage = prevRowFrame;
Packit f0b94e
          isTopOfPage = (lastRowThisPage == firstRowThisPage) &&
Packit f0b94e
                        aReflowInput.mFlags.mIsTopOfPage;
Packit f0b94e
          aStatus.Reset();
Packit f0b94e
          aStatus.SetIncomplete();
Packit f0b94e
        } else {
Packit f0b94e
          // We can't push children, so let our parent reflow us again with more
Packit f0b94e
          // space
Packit f0b94e
          aDesiredSize.Height() = rowRect.YMost();
Packit f0b94e
          aStatus.Reset();
Packit f0b94e
          break;
Packit f0b94e
        }
Packit f0b94e
      }
Packit f0b94e
      // reflow the cells with rowspan >1 that occur on the page
Packit f0b94e
Packit f0b94e
      nsTableRowFrame* firstTruncatedRow;
Packit f0b94e
      nscoord bMost;
Packit f0b94e
      SplitSpanningCells(*aPresContext, aReflowInput, *aTableFrame,
Packit f0b94e
                         *firstRowThisPage, *lastRowThisPage,
Packit f0b94e
                         aReflowInput.mFlags.mIsTopOfPage, spanningRowBottom,
Packit f0b94e
                         contRow, firstTruncatedRow, bMost);
Packit f0b94e
      if (firstTruncatedRow) {
Packit f0b94e
        // A rowspan >1 cell did not fit (and could not split) in the space we
Packit f0b94e
        // gave it
Packit f0b94e
        if (firstTruncatedRow == firstRowThisPage) {
Packit f0b94e
          if (aReflowInput.mFlags.mIsTopOfPage) {
Packit f0b94e
            NS_WARNING("data loss in a row spanned cell");
Packit f0b94e
          } else {
Packit f0b94e
            // We can't push children, so let our parent reflow us again with
Packit f0b94e
            // more space
Packit f0b94e
            aDesiredSize.Height() = rowRect.YMost();
Packit f0b94e
            aStatus.Reset();
Packit f0b94e
            UndoContinuedRow(aPresContext, contRow);
Packit f0b94e
            contRow = nullptr;
Packit f0b94e
          }
Packit f0b94e
        } else {  // (firstTruncatedRow != firstRowThisPage)
Packit f0b94e
          // Try to put firstTruncateRow on the next page
Packit f0b94e
          nsTableRowFrame* rowBefore =
Packit f0b94e
              ::GetRowBefore(*firstRowThisPage, *firstTruncatedRow);
Packit f0b94e
          nscoord oldSpanningRowBottom = spanningRowBottom;
Packit f0b94e
          spanningRowBottom = rowBefore->GetNormalRect().YMost();
Packit f0b94e
Packit f0b94e
          UndoContinuedRow(aPresContext, contRow);
Packit f0b94e
          contRow = nullptr;
Packit f0b94e
          nsTableRowFrame* oldLastRowThisPage = lastRowThisPage;
Packit f0b94e
          lastRowThisPage = rowBefore;
Packit f0b94e
          aStatus.Reset();
Packit f0b94e
          aStatus.SetIncomplete();
Packit f0b94e
Packit f0b94e
          // Call SplitSpanningCells again with rowBefore as the last row on the
Packit f0b94e
          // page
Packit f0b94e
          SplitSpanningCells(
Packit f0b94e
              *aPresContext, aReflowInput, *aTableFrame, *firstRowThisPage,
Packit f0b94e
              *rowBefore, aReflowInput.mFlags.mIsTopOfPage, spanningRowBottom,
Packit f0b94e
              contRow, firstTruncatedRow, aDesiredSize.Height());
Packit f0b94e
          if (firstTruncatedRow) {
Packit f0b94e
            if (aReflowInput.mFlags.mIsTopOfPage) {
Packit f0b94e
              // We were better off with the 1st call to SplitSpanningCells, do
Packit f0b94e
              // it again
Packit f0b94e
              UndoContinuedRow(aPresContext, contRow);
Packit f0b94e
              contRow = nullptr;
Packit f0b94e
              lastRowThisPage = oldLastRowThisPage;
Packit f0b94e
              spanningRowBottom = oldSpanningRowBottom;
Packit f0b94e
              SplitSpanningCells(*aPresContext, aReflowInput, *aTableFrame,
Packit f0b94e
                                 *firstRowThisPage, *lastRowThisPage,
Packit f0b94e
                                 aReflowInput.mFlags.mIsTopOfPage,
Packit f0b94e
                                 spanningRowBottom, contRow, firstTruncatedRow,
Packit f0b94e
                                 aDesiredSize.Height());
Packit f0b94e
              NS_WARNING("data loss in a row spanned cell");
Packit f0b94e
            } else {
Packit f0b94e
              // Let our parent reflow us again with more space
Packit f0b94e
              aDesiredSize.Height() = rowRect.YMost();
Packit f0b94e
              aStatus.Reset();
Packit f0b94e
              UndoContinuedRow(aPresContext, contRow);
Packit f0b94e
              contRow = nullptr;
Packit f0b94e
            }
Packit f0b94e
          }
Packit f0b94e
        }  // if (firstTruncatedRow == firstRowThisPage)
Packit f0b94e
      }    // if (firstTruncatedRow)
Packit f0b94e
      else {
Packit f0b94e
        aDesiredSize.Height() = std::max(aDesiredSize.Height(), bMost);
Packit f0b94e
        if (contRow) {
Packit f0b94e
          aStatus.Reset();
Packit f0b94e
          aStatus.SetIncomplete();
Packit f0b94e
        }
Packit f0b94e
      }
Packit f0b94e
      if (aStatus.IsIncomplete() && !contRow) {
Packit f0b94e
        nsTableRowFrame* nextRow = lastRowThisPage->GetNextRow();
Packit f0b94e
        if (nextRow) {
Packit f0b94e
          PushChildren(nextRow, lastRowThisPage);
Packit f0b94e
        }
Packit f0b94e
      }
Packit f0b94e
      break;
Packit f0b94e
    }  // if (rowRect.YMost() > availHeight)
Packit f0b94e
    else {
Packit f0b94e
      aDesiredSize.Height() = rowRect.YMost();
Packit f0b94e
      prevRowFrame = rowFrame;
Packit f0b94e
      // see if there is a page break after the row
Packit f0b94e
      nsTableRowFrame* nextRow = rowFrame->GetNextRow();
Packit f0b94e
      if (nextRow && nsTableFrame::PageBreakAfter(rowFrame, nextRow)) {
Packit f0b94e
        PushChildren(nextRow, rowFrame);
Packit f0b94e
        aStatus.Reset();
Packit f0b94e
        aStatus.SetIncomplete();
Packit f0b94e
        break;
Packit f0b94e
      }
Packit f0b94e
    }
Packit f0b94e
    // after the 1st row that has a height, we can't be on top
Packit f0b94e
    // of the page anymore.
Packit f0b94e
    isTopOfPage = isTopOfPage && rowRect.YMost() == 0;
Packit f0b94e
  }
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/** Layout the entire row group.
Packit f0b94e
 * This method stacks rows vertically according to HTML 4.0 rules.
Packit f0b94e
 * Rows are responsible for layout of their children.
Packit f0b94e
 */
Packit f0b94e
void nsTableRowGroupFrame::Reflow(nsPresContext* aPresContext,
Packit f0b94e
                                  ReflowOutput& aDesiredSize,
Packit f0b94e
                                  const ReflowInput& aReflowInput,
Packit f0b94e
                                  nsReflowStatus& aStatus) {
Packit f0b94e
  MarkInReflow();
Packit f0b94e
  DO_GLOBAL_REFLOW_COUNT("nsTableRowGroupFrame");
Packit f0b94e
  DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
Packit f0b94e
  MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
Packit f0b94e
Packit f0b94e
  // Row geometry may be going to change so we need to invalidate any row
Packit f0b94e
  // cursor.
Packit f0b94e
  ClearRowCursor();
Packit f0b94e
Packit f0b94e
  // see if a special bsize reflow needs to occur due to having a pct bsize
Packit f0b94e
  nsTableFrame::CheckRequestSpecialBSizeReflow(aReflowInput);
Packit f0b94e
Packit f0b94e
  nsTableFrame* tableFrame = GetTableFrame();
Packit f0b94e
  TableRowGroupReflowInput state(aReflowInput, tableFrame);
Packit f0b94e
  const nsStyleVisibility* groupVis = StyleVisibility();
Packit f0b94e
  bool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE == groupVis->mVisible);
Packit f0b94e
  if (collapseGroup) {
Packit f0b94e
    tableFrame->SetNeedToCollapse(true);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // Check for an overflow list
Packit f0b94e
  MoveOverflowToChildList();
Packit f0b94e
Packit f0b94e
  // Reflow the existing frames.
Packit f0b94e
  bool splitDueToPageBreak = false;
Packit f0b94e
  ReflowChildren(aPresContext, aDesiredSize, state, aStatus,
Packit f0b94e
                 &splitDueToPageBreak);
Packit f0b94e
Packit f0b94e
  // See if all the frames fit. Do not try to split anything if we're
Packit f0b94e
  // not paginated ... we can't split across columns yet.
Packit f0b94e
  if (aReflowInput.mFlags.mTableIsSplittable &&
Packit f0b94e
      NS_UNCONSTRAINEDSIZE != aReflowInput.AvailableHeight() &&
Packit f0b94e
      (aStatus.IsIncomplete() || splitDueToPageBreak ||
Packit f0b94e
       aDesiredSize.Height() > aReflowInput.AvailableHeight())) {
Packit f0b94e
    // Nope, find a place to split the row group
Packit f0b94e
    bool specialReflow = (bool)aReflowInput.mFlags.mSpecialBSizeReflow;
Packit f0b94e
    ((ReflowInput::ReflowInputFlags&)aReflowInput.mFlags).mSpecialBSizeReflow =
Packit f0b94e
        false;
Packit f0b94e
Packit f0b94e
    SplitRowGroup(aPresContext, aDesiredSize, aReflowInput, tableFrame, aStatus,
Packit f0b94e
                  splitDueToPageBreak);
Packit f0b94e
Packit f0b94e
    ((ReflowInput::ReflowInputFlags&)aReflowInput.mFlags).mSpecialBSizeReflow =
Packit f0b94e
        specialReflow;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // XXXmats The following is just bogus.  We leave it here for now because
Packit f0b94e
  // ReflowChildren should pull up rows from our next-in-flow before returning
Packit f0b94e
  // a Complete status, but doesn't (bug 804888).
Packit f0b94e
  if (GetNextInFlow() && GetNextInFlow()->PrincipalChildList().FirstChild()) {
Packit f0b94e
    aStatus.SetIncomplete();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  SetHasStyleBSize((NS_UNCONSTRAINEDSIZE != aReflowInput.ComputedBSize()) &&
Packit f0b94e
                   (aReflowInput.ComputedBSize() > 0));
Packit f0b94e
Packit f0b94e
  // Just set our isize to what was available.
Packit f0b94e
  // The table will calculate the isize and not use our value.
Packit f0b94e
  WritingMode wm = aReflowInput.GetWritingMode();
Packit f0b94e
  aDesiredSize.ISize(wm) = aReflowInput.AvailableISize();
Packit f0b94e
Packit f0b94e
  aDesiredSize.UnionOverflowAreasWithDesiredBounds();
Packit f0b94e
Packit f0b94e
  // If our parent is in initial reflow, it'll handle invalidating our
Packit f0b94e
  // entire overflow rect.
Packit f0b94e
  if (!GetParent()->HasAnyStateBits(NS_FRAME_FIRST_REFLOW) &&
Packit f0b94e
      nsSize(aDesiredSize.Width(), aDesiredSize.Height()) != mRect.Size()) {
Packit f0b94e
    InvalidateFrame();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  FinishAndStoreOverflow(&aDesiredSize);
Packit f0b94e
Packit f0b94e
  // Any absolutely-positioned children will get reflowed in
Packit f0b94e
  // nsFrame::FixupPositionedTableParts in another pass, so propagate our
Packit f0b94e
  // dirtiness to them before our parent clears our dirty bits.
Packit f0b94e
  PushDirtyBitToAbsoluteFrames();
Packit f0b94e
Packit f0b94e
  NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
bool nsTableRowGroupFrame::ComputeCustomOverflow(
Packit f0b94e
    nsOverflowAreas& aOverflowAreas) {
Packit f0b94e
  // Row cursor invariants depend on the visual overflow area of the rows,
Packit f0b94e
  // which may have changed, so we need to clear the cursor now.
Packit f0b94e
  ClearRowCursor();
Packit f0b94e
  return nsContainerFrame::ComputeCustomOverflow(aOverflowAreas);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* virtual */ void nsTableRowGroupFrame::DidSetStyleContext(
Packit f0b94e
    nsStyleContext* aOldStyleContext) {
Packit f0b94e
  nsContainerFrame::DidSetStyleContext(aOldStyleContext);
Packit f0b94e
Packit f0b94e
  if (!aOldStyleContext)  // avoid this on init
Packit f0b94e
    return;
Packit f0b94e
Packit f0b94e
  nsTableFrame* tableFrame = GetTableFrame();
Packit f0b94e
  if (tableFrame->IsBorderCollapse() &&
Packit f0b94e
      tableFrame->BCRecalcNeeded(aOldStyleContext, StyleContext())) {
Packit f0b94e
    TableArea damageArea(0, GetStartRowIndex(), tableFrame->GetColCount(),
Packit f0b94e
                         GetRowCount());
Packit f0b94e
    tableFrame->AddBCDamageArea(damageArea);
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void nsTableRowGroupFrame::AppendFrames(ChildListID aListID,
Packit f0b94e
                                        nsFrameList& aFrameList) {
Packit f0b94e
  NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
Packit f0b94e
Packit f0b94e
  DrainSelfOverflowList();  // ensure the last frame is in mFrames
Packit f0b94e
  ClearRowCursor();
Packit f0b94e
Packit f0b94e
  // collect the new row frames in an array
Packit f0b94e
  // XXXbz why are we doing the QI stuff?  There shouldn't be any non-rows here.
Packit f0b94e
  AutoTArray<nsTableRowFrame*, 8> rows;
Packit f0b94e
  for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
Packit f0b94e
    nsTableRowFrame* rowFrame = do_QueryFrame(e.get());
Packit f0b94e
    NS_ASSERTION(rowFrame, "Unexpected frame; frame constructor screwed up");
Packit f0b94e
    if (rowFrame) {
Packit f0b94e
      NS_ASSERTION(
Packit f0b94e
          mozilla::StyleDisplay::TableRow == e.get()->StyleDisplay()->mDisplay,
Packit f0b94e
          "wrong display type on rowframe");
Packit f0b94e
      rows.AppendElement(rowFrame);
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  int32_t rowIndex = GetRowCount();
Packit f0b94e
  // Append the frames to the sibling chain
Packit f0b94e
  mFrames.AppendFrames(nullptr, aFrameList);
Packit f0b94e
Packit f0b94e
  if (rows.Length() > 0) {
Packit f0b94e
    nsTableFrame* tableFrame = GetTableFrame();
Packit f0b94e
    tableFrame->AppendRows(this, rowIndex, rows);
Packit f0b94e
    PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange,
Packit f0b94e
                                  NS_FRAME_HAS_DIRTY_CHILDREN);
Packit f0b94e
    tableFrame->SetGeometryDirty();
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void nsTableRowGroupFrame::InsertFrames(ChildListID aListID,
Packit f0b94e
                                        nsIFrame* aPrevFrame,
Packit f0b94e
                                        nsFrameList& aFrameList) {
Packit f0b94e
  NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
Packit f0b94e
  NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
Packit f0b94e
               "inserting after sibling frame with different parent");
Packit f0b94e
Packit f0b94e
  DrainSelfOverflowList();  // ensure aPrevFrame is in mFrames
Packit f0b94e
  ClearRowCursor();
Packit f0b94e
Packit f0b94e
  // collect the new row frames in an array
Packit f0b94e
  // XXXbz why are we doing the QI stuff?  There shouldn't be any non-rows here.
Packit f0b94e
  nsTableFrame* tableFrame = GetTableFrame();
Packit f0b94e
  nsTArray<nsTableRowFrame*> rows;
Packit f0b94e
  bool gotFirstRow = false;
Packit f0b94e
  for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
Packit f0b94e
    nsTableRowFrame* rowFrame = do_QueryFrame(e.get());
Packit f0b94e
    NS_ASSERTION(rowFrame, "Unexpected frame; frame constructor screwed up");
Packit f0b94e
    if (rowFrame) {
Packit f0b94e
      NS_ASSERTION(
Packit f0b94e
          mozilla::StyleDisplay::TableRow == e.get()->StyleDisplay()->mDisplay,
Packit f0b94e
          "wrong display type on rowframe");
Packit f0b94e
      rows.AppendElement(rowFrame);
Packit f0b94e
      if (!gotFirstRow) {
Packit f0b94e
        rowFrame->SetFirstInserted(true);
Packit f0b94e
        gotFirstRow = true;
Packit f0b94e
        tableFrame->SetRowInserted(true);
Packit f0b94e
      }
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  int32_t startRowIndex = GetStartRowIndex();
Packit f0b94e
  // Insert the frames in the sibling chain
Packit f0b94e
  mFrames.InsertFrames(nullptr, aPrevFrame, aFrameList);
Packit f0b94e
Packit f0b94e
  int32_t numRows = rows.Length();
Packit f0b94e
  if (numRows > 0) {
Packit f0b94e
    nsTableRowFrame* prevRow =
Packit f0b94e
        (nsTableRowFrame*)nsTableFrame::GetFrameAtOrBefore(
Packit f0b94e
            this, aPrevFrame, LayoutFrameType::TableRow);
Packit f0b94e
    int32_t rowIndex = (prevRow) ? prevRow->GetRowIndex() + 1 : startRowIndex;
Packit f0b94e
    tableFrame->InsertRows(this, rows, rowIndex, true);
Packit f0b94e
Packit f0b94e
    PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange,
Packit f0b94e
                                  NS_FRAME_HAS_DIRTY_CHILDREN);
Packit f0b94e
    tableFrame->SetGeometryDirty();
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void nsTableRowGroupFrame::RemoveFrame(ChildListID aListID,
Packit f0b94e
                                       nsIFrame* aOldFrame) {
Packit f0b94e
  NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
Packit f0b94e
Packit f0b94e
  ClearRowCursor();
Packit f0b94e
Packit f0b94e
  // XXX why are we doing the QI stuff?  There shouldn't be any non-rows here.
Packit f0b94e
  nsTableRowFrame* rowFrame = do_QueryFrame(aOldFrame);
Packit f0b94e
  if (rowFrame) {
Packit f0b94e
    nsTableFrame* tableFrame = GetTableFrame();
Packit f0b94e
    // remove the rows from the table (and flag a rebalance)
Packit f0b94e
    tableFrame->RemoveRows(*rowFrame, 1, true);
Packit f0b94e
Packit f0b94e
    PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange,
Packit f0b94e
                                  NS_FRAME_HAS_DIRTY_CHILDREN);
Packit f0b94e
    tableFrame->SetGeometryDirty();
Packit f0b94e
  }
Packit f0b94e
  mFrames.DestroyFrame(aOldFrame);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* virtual */ nsMargin nsTableRowGroupFrame::GetUsedMargin() const {
Packit f0b94e
  return nsMargin(0, 0, 0, 0);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* virtual */ nsMargin nsTableRowGroupFrame::GetUsedBorder() const {
Packit f0b94e
  return nsMargin(0, 0, 0, 0);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* virtual */ nsMargin nsTableRowGroupFrame::GetUsedPadding() const {
Packit f0b94e
  return nsMargin(0, 0, 0, 0);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
nscoord nsTableRowGroupFrame::GetBSizeBasis(const ReflowInput& aReflowInput) {
Packit f0b94e
  nscoord result = 0;
Packit f0b94e
  nsTableFrame* tableFrame = GetTableFrame();
Packit f0b94e
  int32_t startRowIndex = GetStartRowIndex();
Packit f0b94e
  if ((aReflowInput.ComputedBSize() > 0) &&
Packit f0b94e
      (aReflowInput.ComputedBSize() < NS_UNCONSTRAINEDSIZE)) {
Packit f0b94e
    nscoord cellSpacing = tableFrame->GetRowSpacing(
Packit f0b94e
        startRowIndex,
Packit f0b94e
        std::max(startRowIndex, startRowIndex + GetRowCount() - 1));
Packit f0b94e
    result = aReflowInput.ComputedBSize() - cellSpacing;
Packit f0b94e
  } else {
Packit f0b94e
    const ReflowInput* parentRI = aReflowInput.mParentReflowInput;
Packit f0b94e
    if (parentRI && (tableFrame != parentRI->mFrame)) {
Packit f0b94e
      parentRI = parentRI->mParentReflowInput;
Packit f0b94e
    }
Packit f0b94e
    if (parentRI && (tableFrame == parentRI->mFrame) &&
Packit f0b94e
        (parentRI->ComputedBSize() > 0) &&
Packit f0b94e
        (parentRI->ComputedBSize() < NS_UNCONSTRAINEDSIZE)) {
Packit f0b94e
      nscoord cellSpacing =
Packit f0b94e
          tableFrame->GetRowSpacing(-1, tableFrame->GetRowCount());
Packit f0b94e
      result = parentRI->ComputedBSize() - cellSpacing;
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return result;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
bool nsTableRowGroupFrame::IsSimpleRowFrame(nsTableFrame* aTableFrame,
Packit f0b94e
                                            nsTableRowFrame* aRowFrame) {
Packit f0b94e
  int32_t rowIndex = aRowFrame->GetRowIndex();
Packit f0b94e
Packit f0b94e
  // It's a simple row frame if there are no cells that span into or
Packit f0b94e
  // across the row
Packit f0b94e
  int32_t numEffCols = aTableFrame->GetEffectiveColCount();
Packit f0b94e
  if (!aTableFrame->RowIsSpannedInto(rowIndex, numEffCols) &&
Packit f0b94e
      !aTableFrame->RowHasSpanningCells(rowIndex, numEffCols)) {
Packit f0b94e
    return true;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return false;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/** find page break before the first row **/
Packit f0b94e
bool nsTableRowGroupFrame::HasInternalBreakBefore() const {
Packit f0b94e
  nsIFrame* firstChild = mFrames.FirstChild();
Packit f0b94e
  if (!firstChild) return false;
Packit f0b94e
  return firstChild->StyleDisplay()->mBreakBefore;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/** find page break after the last row **/
Packit f0b94e
bool nsTableRowGroupFrame::HasInternalBreakAfter() const {
Packit f0b94e
  nsIFrame* lastChild = mFrames.LastChild();
Packit f0b94e
  if (!lastChild) return false;
Packit f0b94e
  return lastChild->StyleDisplay()->mBreakAfter;
Packit f0b94e
}
Packit f0b94e
/* ----- global methods ----- */
Packit f0b94e
Packit f0b94e
nsTableRowGroupFrame* NS_NewTableRowGroupFrame(nsIPresShell* aPresShell,
Packit f0b94e
                                               nsStyleContext* aContext) {
Packit f0b94e
  return new (aPresShell) nsTableRowGroupFrame(aContext);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMPL_FRAMEARENA_HELPERS(nsTableRowGroupFrame)
Packit f0b94e
Packit f0b94e
#ifdef DEBUG_FRAME_DUMP
Packit f0b94e
nsresult nsTableRowGroupFrame::GetFrameName(nsAString& aResult) const {
Packit f0b94e
  return MakeFrameName(NS_LITERAL_STRING("TableRowGroup"), aResult);
Packit f0b94e
}
Packit f0b94e
#endif
Packit f0b94e
Packit f0b94e
LogicalMargin nsTableRowGroupFrame::GetBCBorderWidth(WritingMode aWM) {
Packit f0b94e
  LogicalMargin border(aWM);
Packit f0b94e
  nsTableRowFrame* firstRowFrame = nullptr;
Packit f0b94e
  nsTableRowFrame* lastRowFrame = nullptr;
Packit f0b94e
  for (nsTableRowFrame* rowFrame = GetFirstRow(); rowFrame;
Packit f0b94e
       rowFrame = rowFrame->GetNextRow()) {
Packit f0b94e
    if (!firstRowFrame) {
Packit f0b94e
      firstRowFrame = rowFrame;
Packit f0b94e
    }
Packit f0b94e
    lastRowFrame = rowFrame;
Packit f0b94e
  }
Packit f0b94e
  if (firstRowFrame) {
Packit f0b94e
    border.BStart(aWM) = PresContext()->DevPixelsToAppUnits(
Packit f0b94e
        firstRowFrame->GetBStartBCBorderWidth());
Packit f0b94e
    border.BEnd(aWM) = PresContext()->DevPixelsToAppUnits(
Packit f0b94e
        lastRowFrame->GetBEndBCBorderWidth());
Packit f0b94e
  }
Packit f0b94e
  return border;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void nsTableRowGroupFrame::SetContinuousBCBorderWidth(LogicalSide aForSide,
Packit f0b94e
                                                      BCPixelSize aPixelValue) {
Packit f0b94e
  switch (aForSide) {
Packit f0b94e
    case eLogicalSideIEnd:
Packit f0b94e
      mIEndContBorderWidth = aPixelValue;
Packit f0b94e
      return;
Packit f0b94e
    case eLogicalSideBEnd:
Packit f0b94e
      mBEndContBorderWidth = aPixelValue;
Packit f0b94e
      return;
Packit f0b94e
    case eLogicalSideIStart:
Packit f0b94e
      mIStartContBorderWidth = aPixelValue;
Packit f0b94e
      return;
Packit f0b94e
    default:
Packit f0b94e
      NS_ERROR("invalid LogicalSide argument");
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
// nsILineIterator methods
Packit f0b94e
int32_t nsTableRowGroupFrame::GetNumLines() { return GetRowCount(); }
Packit f0b94e
Packit f0b94e
bool nsTableRowGroupFrame::GetDirection() {
Packit f0b94e
  return (NS_STYLE_DIRECTION_RTL ==
Packit f0b94e
          GetTableFrame()->StyleVisibility()->mDirection);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
nsTableRowGroupFrame::GetLine(int32_t aLineNumber, nsIFrame** aFirstFrameOnLine,
Packit f0b94e
                              int32_t* aNumFramesOnLine, nsRect& aLineBounds) {
Packit f0b94e
  NS_ENSURE_ARG_POINTER(aFirstFrameOnLine);
Packit f0b94e
  NS_ENSURE_ARG_POINTER(aNumFramesOnLine);
Packit f0b94e
Packit f0b94e
  nsTableFrame* table = GetTableFrame();
Packit f0b94e
  nsTableCellMap* cellMap = table->GetCellMap();
Packit f0b94e
Packit f0b94e
  *aFirstFrameOnLine = nullptr;
Packit f0b94e
  *aNumFramesOnLine = 0;
Packit f0b94e
  aLineBounds.SetRect(0, 0, 0, 0);
Packit f0b94e
Packit f0b94e
  if ((aLineNumber < 0) || (aLineNumber >= GetRowCount())) {
Packit f0b94e
    return NS_OK;
Packit f0b94e
  }
Packit f0b94e
  aLineNumber += GetStartRowIndex();
Packit f0b94e
Packit f0b94e
  *aNumFramesOnLine = cellMap->GetNumCellsOriginatingInRow(aLineNumber);
Packit f0b94e
  if (*aNumFramesOnLine == 0) {
Packit f0b94e
    return NS_OK;
Packit f0b94e
  }
Packit f0b94e
  int32_t colCount = table->GetColCount();
Packit f0b94e
  for (int32_t i = 0; i < colCount; i++) {
Packit f0b94e
    CellData* data = cellMap->GetDataAt(aLineNumber, i);
Packit f0b94e
    if (data && data->IsOrig()) {
Packit f0b94e
      *aFirstFrameOnLine = (nsIFrame*)data->GetCellFrame();
Packit f0b94e
      nsIFrame* parent = (*aFirstFrameOnLine)->GetParent();
Packit f0b94e
      aLineBounds = parent->GetRect();
Packit f0b94e
      return NS_OK;
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
  NS_ERROR("cellmap is lying");
Packit f0b94e
  return NS_ERROR_FAILURE;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
int32_t nsTableRowGroupFrame::FindLineContaining(nsIFrame* aFrame,
Packit f0b94e
                                                 int32_t aStartLine) {
Packit f0b94e
  NS_ENSURE_TRUE(aFrame, -1);
Packit f0b94e
Packit f0b94e
  nsTableRowFrame* rowFrame = do_QueryFrame(aFrame);
Packit f0b94e
  NS_ASSERTION(rowFrame, "RowGroup contains a frame that is not a row");
Packit f0b94e
Packit f0b94e
  int32_t rowIndexInGroup = rowFrame->GetRowIndex() - GetStartRowIndex();
Packit f0b94e
Packit f0b94e
  return rowIndexInGroup >= aStartLine ? rowIndexInGroup : -1;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
nsTableRowGroupFrame::CheckLineOrder(int32_t aLine, bool* aIsReordered,
Packit f0b94e
                                     nsIFrame** aFirstVisual,
Packit f0b94e
                                     nsIFrame** aLastVisual) {
Packit f0b94e
  *aIsReordered = false;
Packit f0b94e
  *aFirstVisual = nullptr;
Packit f0b94e
  *aLastVisual = nullptr;
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
nsTableRowGroupFrame::FindFrameAt(int32_t aLineNumber, nsPoint aPos,
Packit f0b94e
                                  nsIFrame** aFrameFound,
Packit f0b94e
                                  bool* aPosIsBeforeFirstFrame,
Packit f0b94e
                                  bool* aPosIsAfterLastFrame) {
Packit f0b94e
  nsTableFrame* table = GetTableFrame();
Packit f0b94e
  nsTableCellMap* cellMap = table->GetCellMap();
Packit f0b94e
Packit f0b94e
  WritingMode wm = table->GetWritingMode();
Packit f0b94e
  nsSize containerSize = table->GetSize();
Packit f0b94e
  LogicalPoint pos(wm, aPos, containerSize);
Packit f0b94e
Packit f0b94e
  *aFrameFound = nullptr;
Packit f0b94e
  *aPosIsBeforeFirstFrame = true;
Packit f0b94e
  *aPosIsAfterLastFrame = false;
Packit f0b94e
Packit f0b94e
  aLineNumber += GetStartRowIndex();
Packit f0b94e
  int32_t numCells = cellMap->GetNumCellsOriginatingInRow(aLineNumber);
Packit f0b94e
  if (numCells == 0) {
Packit f0b94e
    return NS_OK;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  nsIFrame* frame = nullptr;
Packit f0b94e
  int32_t colCount = table->GetColCount();
Packit f0b94e
  for (int32_t i = 0; i < colCount; i++) {
Packit f0b94e
    CellData* data = cellMap->GetDataAt(aLineNumber, i);
Packit f0b94e
    if (data && data->IsOrig()) {
Packit f0b94e
      frame = (nsIFrame*)data->GetCellFrame();
Packit f0b94e
      break;
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
  NS_ASSERTION(frame, "cellmap is lying");
Packit f0b94e
  bool isRTL = (NS_STYLE_DIRECTION_RTL == table->StyleVisibility()->mDirection);
Packit f0b94e
Packit f0b94e
  nsIFrame* closestFromStart = nullptr;
Packit f0b94e
  nsIFrame* closestFromEnd = nullptr;
Packit f0b94e
  int32_t n = numCells;
Packit f0b94e
  nsIFrame* firstFrame = frame;
Packit f0b94e
  while (n--) {
Packit f0b94e
    LogicalRect rect = frame->GetLogicalRect(wm, containerSize);
Packit f0b94e
    if (rect.ISize(wm) > 0) {
Packit f0b94e
      // If pos.I() is inside this frame - this is it
Packit f0b94e
      if (rect.IStart(wm) <= pos.I(wm) && rect.IEnd(wm) > pos.I(wm)) {
Packit f0b94e
        closestFromStart = closestFromEnd = frame;
Packit f0b94e
        break;
Packit f0b94e
      }
Packit f0b94e
      if (rect.IStart(wm) < pos.I(wm)) {
Packit f0b94e
        if (!closestFromStart ||
Packit f0b94e
            rect.IEnd(wm) >
Packit f0b94e
                closestFromStart->GetLogicalRect(wm, containerSize).IEnd(wm))
Packit f0b94e
          closestFromStart = frame;
Packit f0b94e
      } else {
Packit f0b94e
        if (!closestFromEnd ||
Packit f0b94e
            rect.IStart(wm) <
Packit f0b94e
                closestFromEnd->GetLogicalRect(wm, containerSize).IStart(wm))
Packit f0b94e
          closestFromEnd = frame;
Packit f0b94e
      }
Packit f0b94e
    }
Packit f0b94e
    frame = frame->GetNextSibling();
Packit f0b94e
  }
Packit f0b94e
  if (!closestFromStart && !closestFromEnd) {
Packit f0b94e
    // All frames were zero-width. Just take the first one.
Packit f0b94e
    closestFromStart = closestFromEnd = firstFrame;
Packit f0b94e
  }
Packit f0b94e
  *aPosIsBeforeFirstFrame = isRTL ? !closestFromEnd : !closestFromStart;
Packit f0b94e
  *aPosIsAfterLastFrame = isRTL ? !closestFromStart : !closestFromEnd;
Packit f0b94e
  if (closestFromStart == closestFromEnd) {
Packit f0b94e
    *aFrameFound = closestFromStart;
Packit f0b94e
  } else if (!closestFromStart) {
Packit f0b94e
    *aFrameFound = closestFromEnd;
Packit f0b94e
  } else if (!closestFromEnd) {
Packit f0b94e
    *aFrameFound = closestFromStart;
Packit f0b94e
  } else {  // we're between two frames
Packit f0b94e
    nscoord delta =
Packit f0b94e
        closestFromEnd->GetLogicalRect(wm, containerSize).IStart(wm) -
Packit f0b94e
        closestFromStart->GetLogicalRect(wm, containerSize).IEnd(wm);
Packit f0b94e
    if (pos.I(wm) <
Packit f0b94e
        closestFromStart->GetLogicalRect(wm, containerSize).IEnd(wm) +
Packit f0b94e
            delta / 2) {
Packit f0b94e
      *aFrameFound = closestFromStart;
Packit f0b94e
    } else {
Packit f0b94e
      *aFrameFound = closestFromEnd;
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
nsTableRowGroupFrame::GetNextSiblingOnLine(nsIFrame*& aFrame,
Packit f0b94e
                                           int32_t aLineNumber) {
Packit f0b94e
  NS_ENSURE_ARG_POINTER(aFrame);
Packit f0b94e
  aFrame = aFrame->GetNextSibling();
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
// end nsLineIterator methods
Packit f0b94e
Packit f0b94e
NS_DECLARE_FRAME_PROPERTY_DELETABLE(RowCursorProperty,
Packit f0b94e
                                    nsTableRowGroupFrame::FrameCursorData)
Packit f0b94e
Packit f0b94e
void nsTableRowGroupFrame::ClearRowCursor() {
Packit f0b94e
  if (!HasAnyStateBits(NS_ROWGROUP_HAS_ROW_CURSOR)) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  RemoveStateBits(NS_ROWGROUP_HAS_ROW_CURSOR);
Packit f0b94e
  DeleteProperty(RowCursorProperty());
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
nsTableRowGroupFrame::FrameCursorData* nsTableRowGroupFrame::SetupRowCursor() {
Packit f0b94e
  if (HasAnyStateBits(NS_ROWGROUP_HAS_ROW_CURSOR)) {
Packit f0b94e
    // We already have a valid row cursor. Don't waste time rebuilding it.
Packit f0b94e
    return nullptr;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  nsIFrame* f = mFrames.FirstChild();
Packit f0b94e
  int32_t count;
Packit f0b94e
  for (count = 0; f && count < MIN_ROWS_NEEDING_CURSOR; ++count) {
Packit f0b94e
    f = f->GetNextSibling();
Packit f0b94e
  }
Packit f0b94e
  if (!f) {
Packit f0b94e
    // Less than MIN_ROWS_NEEDING_CURSOR rows, so just don't bother
Packit f0b94e
    return nullptr;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  FrameCursorData* data = new FrameCursorData();
Packit f0b94e
  if (!data) return nullptr;
Packit f0b94e
  SetProperty(RowCursorProperty(), data);
Packit f0b94e
  AddStateBits(NS_ROWGROUP_HAS_ROW_CURSOR);
Packit f0b94e
  return data;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
nsIFrame* nsTableRowGroupFrame::GetFirstRowContaining(nscoord aY,
Packit f0b94e
                                                      nscoord* aOverflowAbove) {
Packit f0b94e
  if (!HasAnyStateBits(NS_ROWGROUP_HAS_ROW_CURSOR)) {
Packit f0b94e
    return nullptr;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  FrameCursorData* property = GetProperty(RowCursorProperty());
Packit f0b94e
  uint32_t cursorIndex = property->mCursorIndex;
Packit f0b94e
  uint32_t frameCount = property->mFrames.Length();
Packit f0b94e
  if (cursorIndex >= frameCount) return nullptr;
Packit f0b94e
  nsIFrame* cursorFrame = property->mFrames[cursorIndex];
Packit f0b94e
Packit f0b94e
  // The cursor's frame list excludes frames with empty overflow-area, so
Packit f0b94e
  // we don't need to check that here.
Packit f0b94e
Packit f0b94e
  // We use property->mOverflowBelow here instead of computing the frame's
Packit f0b94e
  // true overflowArea.YMost(), because it is essential for the thresholds
Packit f0b94e
  // to form a monotonically increasing sequence. Otherwise we would break
Packit f0b94e
  // encountering a row whose overflowArea.YMost() is <= aY but which has
Packit f0b94e
  // a row above it containing cell(s) that span to include aY.
Packit f0b94e
  while (cursorIndex > 0 &&
Packit f0b94e
         cursorFrame->GetNormalRect().YMost() + property->mOverflowBelow > aY) {
Packit f0b94e
    --cursorIndex;
Packit f0b94e
    cursorFrame = property->mFrames[cursorIndex];
Packit f0b94e
  }
Packit f0b94e
  while (cursorIndex + 1 < frameCount &&
Packit f0b94e
         cursorFrame->GetNormalRect().YMost() + property->mOverflowBelow <=
Packit f0b94e
             aY) {
Packit f0b94e
    ++cursorIndex;
Packit f0b94e
    cursorFrame = property->mFrames[cursorIndex];
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  property->mCursorIndex = cursorIndex;
Packit f0b94e
  *aOverflowAbove = property->mOverflowAbove;
Packit f0b94e
  return cursorFrame;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
bool nsTableRowGroupFrame::FrameCursorData::AppendFrame(nsIFrame* aFrame) {
Packit f0b94e
  // Relative positioning can cause table parts to move, but we will still paint
Packit f0b94e
  // the backgrounds for the parts under them at their 'normal' position. That
Packit f0b94e
  // means that we must consider the overflow rects at both positions. For
Packit f0b94e
  // example, if we use relative positioning to move a row-spanning cell, we
Packit f0b94e
  // will still paint the row background for that cell at its normal position,
Packit f0b94e
  // which will overflow the row.
Packit f0b94e
  // XXX(seth): This probably isn't correct in the presence of transforms.
Packit f0b94e
  nsRect positionedOverflowRect = aFrame->GetVisualOverflowRect();
Packit f0b94e
  nsPoint positionedToNormal =
Packit f0b94e
      aFrame->GetNormalPosition() - aFrame->GetPosition();
Packit f0b94e
  nsRect normalOverflowRect = positionedOverflowRect + positionedToNormal;
Packit f0b94e
Packit f0b94e
  nsRect overflowRect = positionedOverflowRect.Union(normalOverflowRect);
Packit f0b94e
  if (overflowRect.IsEmpty()) return true;
Packit f0b94e
  nscoord overflowAbove = -overflowRect.y;
Packit f0b94e
  nscoord overflowBelow = overflowRect.YMost() - aFrame->GetSize().height;
Packit f0b94e
  mOverflowAbove = std::max(mOverflowAbove, overflowAbove);
Packit f0b94e
  mOverflowBelow = std::max(mOverflowBelow, overflowBelow);
Packit f0b94e
  return mFrames.AppendElement(aFrame) != nullptr;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void nsTableRowGroupFrame::InvalidateFrame(uint32_t aDisplayItemKey) {
Packit f0b94e
  nsIFrame::InvalidateFrame(aDisplayItemKey);
Packit f0b94e
  if (GetTableFrame()->IsBorderCollapse()) {
Packit f0b94e
    GetParent()->InvalidateFrameWithRect(
Packit f0b94e
        GetVisualOverflowRect() + GetPosition(), aDisplayItemKey);
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void nsTableRowGroupFrame::InvalidateFrameWithRect(const nsRect& aRect,
Packit f0b94e
                                                   uint32_t aDisplayItemKey) {
Packit f0b94e
  nsIFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey);
Packit f0b94e
  // If we have filters applied that would affects our bounds, then
Packit f0b94e
  // we get an inactive layer created and this is computed
Packit f0b94e
  // within FrameLayerBuilder
Packit f0b94e
  GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey);
Packit f0b94e
}