layout/tables/nsTableRowFrame.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/tables/nsTableRowFrame.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1451 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +#include "nsTableRowFrame.h"
     1.9 +#include "nsTableRowGroupFrame.h"
    1.10 +#include "nsIPresShell.h"
    1.11 +#include "nsPresContext.h"
    1.12 +#include "nsStyleContext.h"
    1.13 +#include "nsStyleConsts.h"
    1.14 +#include "nsGkAtoms.h"
    1.15 +#include "nsIContent.h"
    1.16 +#include "nsTableFrame.h"
    1.17 +#include "nsTableCellFrame.h"
    1.18 +#include "nsCSSRendering.h"
    1.19 +#include "nsHTMLParts.h"
    1.20 +#include "nsTableColGroupFrame.h"
    1.21 +#include "nsTableColFrame.h"
    1.22 +#include "nsCOMPtr.h"
    1.23 +#include "nsDisplayList.h"
    1.24 +#include "nsIFrameInlines.h"
    1.25 +#include <algorithm>
    1.26 +
    1.27 +using namespace mozilla;
    1.28 +
    1.29 +struct nsTableCellReflowState : public nsHTMLReflowState
    1.30 +{
    1.31 +  nsTableCellReflowState(nsPresContext*           aPresContext,
    1.32 +                         const nsHTMLReflowState& aParentReflowState,
    1.33 +                         nsIFrame*                aFrame,
    1.34 +                         const nsSize&            aAvailableSpace,
    1.35 +                         uint32_t                 aFlags = 0)
    1.36 +    : nsHTMLReflowState(aPresContext, aParentReflowState, aFrame,
    1.37 +                        aAvailableSpace, -1, -1, aFlags)
    1.38 +  {
    1.39 +  }
    1.40 +
    1.41 +  void FixUp(const nsSize& aAvailSpace);
    1.42 +};
    1.43 +
    1.44 +void nsTableCellReflowState::FixUp(const nsSize& aAvailSpace)
    1.45 +{
    1.46 +  // fix the mComputed values during a pass 2 reflow since the cell can be a percentage base
    1.47 +  NS_WARN_IF_FALSE(NS_UNCONSTRAINEDSIZE != aAvailSpace.width,
    1.48 +                   "have unconstrained width; this should only result from "
    1.49 +                   "very large sizes, not attempts at intrinsic width "
    1.50 +                   "calculation");
    1.51 +  if (NS_UNCONSTRAINEDSIZE != ComputedWidth()) {
    1.52 +    nscoord computedWidth =
    1.53 +      aAvailSpace.width - mComputedBorderPadding.LeftRight();
    1.54 +    computedWidth = std::max(0, computedWidth);
    1.55 +    SetComputedWidth(computedWidth);
    1.56 +  }
    1.57 +  if (NS_UNCONSTRAINEDSIZE != ComputedHeight() &&
    1.58 +      NS_UNCONSTRAINEDSIZE != aAvailSpace.height) {
    1.59 +    nscoord computedHeight =
    1.60 +      aAvailSpace.height - mComputedBorderPadding.TopBottom();
    1.61 +    computedHeight = std::max(0, computedHeight);
    1.62 +    SetComputedHeight(computedHeight);
    1.63 +  }
    1.64 +}
    1.65 +
    1.66 +void
    1.67 +nsTableRowFrame::InitChildReflowState(nsPresContext&         aPresContext,
    1.68 +                                      const nsSize&           aAvailSize,
    1.69 +                                      bool                    aBorderCollapse,
    1.70 +                                      nsTableCellReflowState& aReflowState)
    1.71 +{
    1.72 +  nsMargin collapseBorder;
    1.73 +  nsMargin* pCollapseBorder = nullptr;
    1.74 +  if (aBorderCollapse) {
    1.75 +    // we only reflow cells, so don't need to check frame type
    1.76 +    nsBCTableCellFrame* bcCellFrame = (nsBCTableCellFrame*)aReflowState.frame;
    1.77 +    if (bcCellFrame) {
    1.78 +      pCollapseBorder = bcCellFrame->GetBorderWidth(collapseBorder);
    1.79 +    }
    1.80 +  }
    1.81 +  aReflowState.Init(&aPresContext, -1, -1, pCollapseBorder);
    1.82 +  aReflowState.FixUp(aAvailSize);
    1.83 +}
    1.84 +
    1.85 +void 
    1.86 +nsTableRowFrame::SetFixedHeight(nscoord aValue)
    1.87 +{
    1.88 +  nscoord height = std::max(0, aValue);
    1.89 +  if (HasFixedHeight()) {
    1.90 +    if (height > mStyleFixedHeight) {
    1.91 +      mStyleFixedHeight = height;
    1.92 +    }
    1.93 +  }
    1.94 +  else {
    1.95 +    mStyleFixedHeight = height;
    1.96 +    if (height > 0) {
    1.97 +      SetHasFixedHeight(true);
    1.98 +    }
    1.99 +  }
   1.100 +}
   1.101 +
   1.102 +void 
   1.103 +nsTableRowFrame::SetPctHeight(float  aPctValue,
   1.104 +                              bool aForce)
   1.105 +{
   1.106 +  nscoord height = std::max(0, NSToCoordRound(aPctValue * 100.0f));
   1.107 +  if (HasPctHeight()) {
   1.108 +    if ((height > mStylePctHeight) || aForce) {
   1.109 +      mStylePctHeight = height;
   1.110 +    }
   1.111 +  }
   1.112 +  else {
   1.113 +    mStylePctHeight = height;
   1.114 +    if (height > 0) {
   1.115 +      SetHasPctHeight(true);
   1.116 +    }
   1.117 +  }
   1.118 +}
   1.119 +
   1.120 +/* ----------- nsTableRowFrame ---------- */
   1.121 +
   1.122 +NS_QUERYFRAME_HEAD(nsTableRowFrame)
   1.123 +  NS_QUERYFRAME_ENTRY(nsTableRowFrame)
   1.124 +NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
   1.125 +
   1.126 +nsTableRowFrame::nsTableRowFrame(nsStyleContext* aContext)
   1.127 +  : nsContainerFrame(aContext)
   1.128 +{
   1.129 +  mBits.mRowIndex = mBits.mFirstInserted = 0;
   1.130 +  ResetHeight(0);
   1.131 +}
   1.132 +
   1.133 +nsTableRowFrame::~nsTableRowFrame()
   1.134 +{
   1.135 +}
   1.136 +
   1.137 +void
   1.138 +nsTableRowFrame::Init(nsIContent*      aContent,
   1.139 +                      nsIFrame*        aParent,
   1.140 +                      nsIFrame*        aPrevInFlow)
   1.141 +{
   1.142 +  // Let the base class do its initialization
   1.143 +  nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
   1.144 +
   1.145 +  NS_ASSERTION(NS_STYLE_DISPLAY_TABLE_ROW == StyleDisplay()->mDisplay,
   1.146 +               "wrong display on table row frame");
   1.147 +
   1.148 +  if (aPrevInFlow) {
   1.149 +    // Set the row index
   1.150 +    nsTableRowFrame* rowFrame = (nsTableRowFrame*)aPrevInFlow;
   1.151 +    
   1.152 +    SetRowIndex(rowFrame->GetRowIndex());
   1.153 +  }
   1.154 +}
   1.155 +
   1.156 +void
   1.157 +nsTableRowFrame::DestroyFrom(nsIFrame* aDestructRoot)
   1.158 +{
   1.159 +  if (GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) {
   1.160 +    nsTableFrame::UnregisterPositionedTablePart(this, aDestructRoot);
   1.161 +  }
   1.162 +
   1.163 +  nsContainerFrame::DestroyFrom(aDestructRoot);
   1.164 +}
   1.165 +
   1.166 +/* virtual */ void
   1.167 +nsTableRowFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
   1.168 +{
   1.169 +  nsContainerFrame::DidSetStyleContext(aOldStyleContext);
   1.170 +
   1.171 +  if (!aOldStyleContext) //avoid this on init
   1.172 +    return;
   1.173 +     
   1.174 +  nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
   1.175 +  if (tableFrame->IsBorderCollapse() &&
   1.176 +      tableFrame->BCRecalcNeeded(aOldStyleContext, StyleContext())) {
   1.177 +    nsIntRect damageArea(0, GetRowIndex(), tableFrame->GetColCount(), 1);
   1.178 +    tableFrame->AddBCDamageArea(damageArea);
   1.179 +  }
   1.180 +}
   1.181 +
   1.182 +nsresult
   1.183 +nsTableRowFrame::AppendFrames(ChildListID     aListID,
   1.184 +                              nsFrameList&    aFrameList)
   1.185 +{
   1.186 +  NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
   1.187 +
   1.188 +  const nsFrameList::Slice& newCells = mFrames.AppendFrames(nullptr, aFrameList);
   1.189 +
   1.190 +  // Add the new cell frames to the table
   1.191 +  nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
   1.192 +  for (nsFrameList::Enumerator e(newCells) ; !e.AtEnd(); e.Next()) {
   1.193 +    nsIFrame *childFrame = e.get();
   1.194 +    NS_ASSERTION(IS_TABLE_CELL(childFrame->GetType()),"Not a table cell frame/pseudo frame construction failure");
   1.195 +    tableFrame->AppendCell(static_cast<nsTableCellFrame&>(*childFrame), GetRowIndex());
   1.196 +  }
   1.197 +
   1.198 +  PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange,
   1.199 +                                               NS_FRAME_HAS_DIRTY_CHILDREN);
   1.200 +  tableFrame->SetGeometryDirty();
   1.201 +
   1.202 +  return NS_OK;
   1.203 +}
   1.204 +
   1.205 +
   1.206 +nsresult
   1.207 +nsTableRowFrame::InsertFrames(ChildListID     aListID,
   1.208 +                              nsIFrame*       aPrevFrame,
   1.209 +                              nsFrameList&    aFrameList)
   1.210 +{
   1.211 +  NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
   1.212 +  NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
   1.213 +               "inserting after sibling frame with different parent");
   1.214 +  //Insert Frames in the frame list
   1.215 +  const nsFrameList::Slice& newCells = mFrames.InsertFrames(nullptr, aPrevFrame, aFrameList);
   1.216 +
   1.217 +  // Get the table frame
   1.218 +  nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
   1.219 +  nsIAtom* cellFrameType = tableFrame->IsBorderCollapse() ? nsGkAtoms::bcTableCellFrame : nsGkAtoms::tableCellFrame;
   1.220 +  nsTableCellFrame* prevCellFrame = (nsTableCellFrame *)nsTableFrame::GetFrameAtOrBefore(this, aPrevFrame, cellFrameType);
   1.221 +  nsTArray<nsTableCellFrame*> cellChildren;
   1.222 +  for (nsFrameList::Enumerator e(newCells); !e.AtEnd(); e.Next()) {
   1.223 +    nsIFrame *childFrame = e.get();
   1.224 +    NS_ASSERTION(IS_TABLE_CELL(childFrame->GetType()),"Not a table cell frame/pseudo frame construction failure");
   1.225 +    cellChildren.AppendElement(static_cast<nsTableCellFrame*>(childFrame));
   1.226 +  }
   1.227 +  // insert the cells into the cell map
   1.228 +  int32_t colIndex = -1;
   1.229 +  if (prevCellFrame) {
   1.230 +    prevCellFrame->GetColIndex(colIndex);
   1.231 +  }
   1.232 +  tableFrame->InsertCells(cellChildren, GetRowIndex(), colIndex);
   1.233 +  
   1.234 +  PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange,
   1.235 +                                               NS_FRAME_HAS_DIRTY_CHILDREN);
   1.236 +  tableFrame->SetGeometryDirty();
   1.237 +
   1.238 +  return NS_OK;
   1.239 +}
   1.240 +
   1.241 +nsresult
   1.242 +nsTableRowFrame::RemoveFrame(ChildListID     aListID,
   1.243 +                             nsIFrame*       aOldFrame)
   1.244 +{
   1.245 +  NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
   1.246 +
   1.247 +  nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
   1.248 +  nsTableCellFrame *cellFrame = do_QueryFrame(aOldFrame);
   1.249 +  if (cellFrame) {
   1.250 +    int32_t colIndex;
   1.251 +    cellFrame->GetColIndex(colIndex);
   1.252 +    // remove the cell from the cell map
   1.253 +    tableFrame->RemoveCell(cellFrame, GetRowIndex());
   1.254 +
   1.255 +    // Remove the frame and destroy it
   1.256 +    mFrames.DestroyFrame(aOldFrame);
   1.257 +
   1.258 +    PresContext()->PresShell()->
   1.259 +      FrameNeedsReflow(this, nsIPresShell::eTreeChange,
   1.260 +                       NS_FRAME_HAS_DIRTY_CHILDREN);
   1.261 +    tableFrame->SetGeometryDirty();
   1.262 +  }
   1.263 +  else {
   1.264 +    NS_ERROR("unexpected frame type");
   1.265 +    return NS_ERROR_INVALID_ARG;
   1.266 +  }
   1.267 +
   1.268 +  return NS_OK;
   1.269 +}
   1.270 +
   1.271 +/* virtual */ nsMargin
   1.272 +nsTableRowFrame::GetUsedMargin() const
   1.273 +{
   1.274 +  return nsMargin(0,0,0,0);
   1.275 +}
   1.276 +
   1.277 +/* virtual */ nsMargin
   1.278 +nsTableRowFrame::GetUsedBorder() const
   1.279 +{
   1.280 +  return nsMargin(0,0,0,0);
   1.281 +}
   1.282 +
   1.283 +/* virtual */ nsMargin
   1.284 +nsTableRowFrame::GetUsedPadding() const
   1.285 +{
   1.286 +  return nsMargin(0,0,0,0);
   1.287 +}
   1.288 +
   1.289 +nscoord 
   1.290 +GetHeightOfRowsSpannedBelowFirst(nsTableCellFrame& aTableCellFrame,
   1.291 +                                 nsTableFrame&     aTableFrame)
   1.292 +{
   1.293 +  nscoord height = 0;
   1.294 +  nscoord cellSpacingY = aTableFrame.GetCellSpacingY();
   1.295 +  int32_t rowSpan = aTableFrame.GetEffectiveRowSpan(aTableCellFrame);
   1.296 +  // add in height of rows spanned beyond the 1st one
   1.297 +  nsIFrame* nextRow = aTableCellFrame.GetParent()->GetNextSibling();
   1.298 +  for (int32_t rowX = 1; ((rowX < rowSpan) && nextRow);) {
   1.299 +    if (nsGkAtoms::tableRowFrame == nextRow->GetType()) {
   1.300 +      height += nextRow->GetSize().height;
   1.301 +      rowX++;
   1.302 +    }
   1.303 +    height += cellSpacingY;
   1.304 +    nextRow = nextRow->GetNextSibling();
   1.305 +  }
   1.306 +  return height;
   1.307 +}
   1.308 +
   1.309 +nsTableCellFrame*  
   1.310 +nsTableRowFrame::GetFirstCell() 
   1.311 +{
   1.312 +  nsIFrame* childFrame = mFrames.FirstChild();
   1.313 +  while (childFrame) {
   1.314 +    nsTableCellFrame *cellFrame = do_QueryFrame(childFrame);
   1.315 +    if (cellFrame) {
   1.316 +      return cellFrame;
   1.317 +    }
   1.318 +    childFrame = childFrame->GetNextSibling();
   1.319 +  }
   1.320 +  return nullptr;
   1.321 +}
   1.322 +
   1.323 +/**
   1.324 + * Post-reflow hook. This is where the table row does its post-processing
   1.325 + */
   1.326 +void
   1.327 +nsTableRowFrame::DidResize()
   1.328 +{
   1.329 +  // Resize and re-align the cell frames based on our row height
   1.330 +  nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
   1.331 +  nsTableIterator iter(*this);
   1.332 +  nsIFrame* childFrame = iter.First();
   1.333 +  
   1.334 +  nsHTMLReflowMetrics desiredSize(GetWritingMode()); // ???
   1.335 +  desiredSize.Width() = mRect.width;
   1.336 +  desiredSize.Height() = mRect.height;
   1.337 +  desiredSize.SetOverflowAreasToDesiredBounds();
   1.338 +
   1.339 +  while (childFrame) {
   1.340 +    nsTableCellFrame *cellFrame = do_QueryFrame(childFrame);
   1.341 +    if (cellFrame) {
   1.342 +      nscoord cellHeight = mRect.height + GetHeightOfRowsSpannedBelowFirst(*cellFrame, *tableFrame);
   1.343 +
   1.344 +      // resize the cell's height
   1.345 +      nsRect cellRect = cellFrame->GetRect();
   1.346 +      nsRect cellVisualOverflow = cellFrame->GetVisualOverflowRect();
   1.347 +      if (cellRect.height != cellHeight)
   1.348 +      {
   1.349 +        cellFrame->SetSize(nsSize(cellRect.width, cellHeight));
   1.350 +        nsTableFrame::InvalidateTableFrame(cellFrame, cellRect,
   1.351 +                                           cellVisualOverflow,
   1.352 +                                           false);
   1.353 +      }
   1.354 +
   1.355 +      // realign cell content based on the new height.  We might be able to
   1.356 +      // skip this if the height didn't change... maybe.  Hard to tell.
   1.357 +      cellFrame->VerticallyAlignChild(mMaxCellAscent);
   1.358 +      
   1.359 +      // Always store the overflow, even if the height didn't change, since
   1.360 +      // we'll lose part of our overflow area otherwise.
   1.361 +      ConsiderChildOverflow(desiredSize.mOverflowAreas, cellFrame);
   1.362 +
   1.363 +      // Note that if the cell's *content* needs to change in response
   1.364 +      // to this height, it will get a special height reflow.
   1.365 +    }
   1.366 +    // Get the next child
   1.367 +    childFrame = iter.Next();
   1.368 +  }
   1.369 +  FinishAndStoreOverflow(&desiredSize);
   1.370 +  if (HasView()) {
   1.371 +    nsContainerFrame::SyncFrameViewAfterReflow(PresContext(), this, GetView(),
   1.372 +                                               desiredSize.VisualOverflow(), 0);
   1.373 +  }
   1.374 +  // Let our base class do the usual work
   1.375 +}
   1.376 +
   1.377 +// returns max-ascent amongst all cells that have 'vertical-align: baseline'
   1.378 +// *including* cells with rowspans
   1.379 +nscoord nsTableRowFrame::GetMaxCellAscent() const
   1.380 +{
   1.381 +  return mMaxCellAscent;
   1.382 +}
   1.383 +
   1.384 +nscoord nsTableRowFrame::GetRowBaseline()
   1.385 +{
   1.386 +  if(mMaxCellAscent)
   1.387 +    return mMaxCellAscent;
   1.388 +
   1.389 +  // If we don't have a baseline on any of the cells we go for the lowest 
   1.390 +  // content edge of the inner block frames. 
   1.391 +  // Every table cell has a cell frame with its border and padding. Inside
   1.392 +  // the cell is a block frame. The cell is as high as the tallest cell in
   1.393 +  // the parent row. As a consequence the block frame might not touch both
   1.394 +  // the top and the bottom padding of it parent cell frame at the same time.
   1.395 +  // 
   1.396 +  // bbbbbbbbbbbbbbbbbb             cell border:  b
   1.397 +  // bppppppppppppppppb             cell padding: p
   1.398 +  // bpxxxxxxxxxxxxxxpb             inner block:  x
   1.399 +  // bpx            xpb
   1.400 +  // bpx            xpb
   1.401 +  // bpx            xpb
   1.402 +  // bpxxxxxxxxxxxxxxpb  base line
   1.403 +  // bp              pb
   1.404 +  // bp              pb
   1.405 +  // bppppppppppppppppb
   1.406 +  // bbbbbbbbbbbbbbbbbb
   1.407 +
   1.408 +  nsTableIterator iter(*this);
   1.409 +  nsIFrame* childFrame = iter.First();
   1.410 +  nscoord ascent = 0;
   1.411 +   while (childFrame) {
   1.412 +    if (IS_TABLE_CELL(childFrame->GetType())) {
   1.413 +      nsIFrame* firstKid = childFrame->GetFirstPrincipalChild();
   1.414 +      ascent = std::max(ascent, firstKid->GetRect().YMost());
   1.415 +    }
   1.416 +    // Get the next child
   1.417 +    childFrame = iter.Next();
   1.418 +  }
   1.419 +  return ascent;
   1.420 +}
   1.421 +nscoord
   1.422 +nsTableRowFrame::GetHeight(nscoord aPctBasis) const
   1.423 +{
   1.424 +  nscoord height = 0;
   1.425 +  if ((aPctBasis > 0) && HasPctHeight()) {
   1.426 +    height = NSToCoordRound(GetPctHeight() * (float)aPctBasis);
   1.427 +  }
   1.428 +  if (HasFixedHeight()) {
   1.429 +    height = std::max(height, GetFixedHeight());
   1.430 +  }
   1.431 +  return std::max(height, GetContentHeight());
   1.432 +}
   1.433 +
   1.434 +void 
   1.435 +nsTableRowFrame::ResetHeight(nscoord aFixedHeight)
   1.436 +{
   1.437 +  SetHasFixedHeight(false);
   1.438 +  SetHasPctHeight(false);
   1.439 +  SetFixedHeight(0);
   1.440 +  SetPctHeight(0);
   1.441 +  SetContentHeight(0);
   1.442 +
   1.443 +  if (aFixedHeight > 0) {
   1.444 +    SetFixedHeight(aFixedHeight);
   1.445 +  }
   1.446 +
   1.447 +  mMaxCellAscent = 0;
   1.448 +  mMaxCellDescent = 0;
   1.449 +}
   1.450 +
   1.451 +void
   1.452 +nsTableRowFrame::UpdateHeight(nscoord           aHeight,
   1.453 +                              nscoord           aAscent,
   1.454 +                              nscoord           aDescent,
   1.455 +                              nsTableFrame*     aTableFrame,
   1.456 +                              nsTableCellFrame* aCellFrame)
   1.457 +{
   1.458 +  if (!aTableFrame || !aCellFrame) {
   1.459 +    NS_ASSERTION(false , "invalid call");
   1.460 +    return;
   1.461 +  }
   1.462 +
   1.463 +  if (aHeight != NS_UNCONSTRAINEDSIZE) {
   1.464 +    if (!(aCellFrame->HasVerticalAlignBaseline())) { // only the cell's height matters
   1.465 +      if (GetHeight() < aHeight) {
   1.466 +        int32_t rowSpan = aTableFrame->GetEffectiveRowSpan(*aCellFrame);
   1.467 +        if (rowSpan == 1) {
   1.468 +          SetContentHeight(aHeight);
   1.469 +        }
   1.470 +      }
   1.471 +    }
   1.472 +    else { // the alignment on the baseline can change the height
   1.473 +      NS_ASSERTION((aAscent != NS_UNCONSTRAINEDSIZE) && (aDescent != NS_UNCONSTRAINEDSIZE), "invalid call");
   1.474 +      // see if this is a long ascender
   1.475 +      if (mMaxCellAscent < aAscent) {
   1.476 +        mMaxCellAscent = aAscent;
   1.477 +      }
   1.478 +      // see if this is a long descender and without rowspan
   1.479 +      if (mMaxCellDescent < aDescent) {
   1.480 +        int32_t rowSpan = aTableFrame->GetEffectiveRowSpan(*aCellFrame);
   1.481 +        if (rowSpan == 1) {
   1.482 +          mMaxCellDescent = aDescent;
   1.483 +        }
   1.484 +      }
   1.485 +      // keep the tallest height in sync
   1.486 +      if (GetHeight() < mMaxCellAscent + mMaxCellDescent) {
   1.487 +        SetContentHeight(mMaxCellAscent + mMaxCellDescent);
   1.488 +      }
   1.489 +    }
   1.490 +  }
   1.491 +}
   1.492 +
   1.493 +nscoord
   1.494 +nsTableRowFrame::CalcHeight(const nsHTMLReflowState& aReflowState)
   1.495 +{
   1.496 +  nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
   1.497 +  nscoord computedHeight = (NS_UNCONSTRAINEDSIZE == aReflowState.ComputedHeight())
   1.498 +                            ? 0 : aReflowState.ComputedHeight();
   1.499 +  ResetHeight(computedHeight);
   1.500 +
   1.501 +  const nsStylePosition* position = StylePosition();
   1.502 +  if (position->mHeight.ConvertsToLength()) {
   1.503 +    SetFixedHeight(nsRuleNode::ComputeCoordPercentCalc(position->mHeight, 0));
   1.504 +  }
   1.505 +  else if (eStyleUnit_Percent == position->mHeight.GetUnit()) {
   1.506 +    SetPctHeight(position->mHeight.GetPercentValue());
   1.507 +  }
   1.508 +  // calc() with percentages is treated like 'auto' on table rows.
   1.509 +
   1.510 +  for (nsIFrame* kidFrame = mFrames.FirstChild(); kidFrame;
   1.511 +       kidFrame = kidFrame->GetNextSibling()) {
   1.512 +    nsTableCellFrame *cellFrame = do_QueryFrame(kidFrame);
   1.513 +    if (cellFrame) {
   1.514 +      nsSize desSize = cellFrame->GetDesiredSize();
   1.515 +      if ((NS_UNCONSTRAINEDSIZE == aReflowState.AvailableHeight()) && !GetPrevInFlow()) {
   1.516 +        CalculateCellActualHeight(cellFrame, desSize.height);
   1.517 +      }
   1.518 +      // height may have changed, adjust descent to absorb any excess difference
   1.519 +      nscoord ascent;
   1.520 +       if (!kidFrame->GetFirstPrincipalChild()->GetFirstPrincipalChild())
   1.521 +         ascent = desSize.height;
   1.522 +       else
   1.523 +         ascent = cellFrame->GetCellBaseline();
   1.524 +      nscoord descent = desSize.height - ascent;
   1.525 +      UpdateHeight(desSize.height, ascent, descent, tableFrame, cellFrame);
   1.526 +    }
   1.527 +  }
   1.528 +  return GetHeight();
   1.529 +}
   1.530 +
   1.531 +/**
   1.532 + * We need a custom display item for table row backgrounds. This is only used
   1.533 + * when the table row is the root of a stacking context (e.g., has 'opacity').
   1.534 + * Table row backgrounds can extend beyond the row frame bounds, when
   1.535 + * the row contains row-spanning cells.
   1.536 + */
   1.537 +class nsDisplayTableRowBackground : public nsDisplayTableItem {
   1.538 +public:
   1.539 +  nsDisplayTableRowBackground(nsDisplayListBuilder* aBuilder,
   1.540 +                              nsTableRowFrame* aFrame) :
   1.541 +    nsDisplayTableItem(aBuilder, aFrame) {
   1.542 +    MOZ_COUNT_CTOR(nsDisplayTableRowBackground);
   1.543 +  }
   1.544 +#ifdef NS_BUILD_REFCNT_LOGGING
   1.545 +  virtual ~nsDisplayTableRowBackground() {
   1.546 +    MOZ_COUNT_DTOR(nsDisplayTableRowBackground);
   1.547 +  }
   1.548 +#endif
   1.549 +
   1.550 +  virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
   1.551 +                                         const nsDisplayItemGeometry* aGeometry,
   1.552 +                                         nsRegion *aInvalidRegion) MOZ_OVERRIDE;
   1.553 +  virtual void Paint(nsDisplayListBuilder* aBuilder,
   1.554 +                     nsRenderingContext* aCtx) MOZ_OVERRIDE;
   1.555 +  NS_DISPLAY_DECL_NAME("TableRowBackground", TYPE_TABLE_ROW_BACKGROUND)
   1.556 +};
   1.557 +
   1.558 +void
   1.559 +nsDisplayTableRowBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
   1.560 +                                                       const nsDisplayItemGeometry* aGeometry,
   1.561 +                                                       nsRegion *aInvalidRegion)
   1.562 +{
   1.563 +  if (aBuilder->ShouldSyncDecodeImages()) {
   1.564 +    if (nsTableFrame::AnyTablePartHasUndecodedBackgroundImage(mFrame, mFrame->GetNextSibling())) {
   1.565 +      bool snap;
   1.566 +      aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
   1.567 +    }
   1.568 +  }
   1.569 +
   1.570 +  nsDisplayTableItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
   1.571 +}
   1.572 +
   1.573 +void
   1.574 +nsDisplayTableRowBackground::Paint(nsDisplayListBuilder* aBuilder,
   1.575 +                                   nsRenderingContext* aCtx)
   1.576 +{
   1.577 +  nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(mFrame);
   1.578 +  TableBackgroundPainter painter(tableFrame,
   1.579 +                                 TableBackgroundPainter::eOrigin_TableRow,
   1.580 +                                 mFrame->PresContext(), *aCtx,
   1.581 +                                 mVisibleRect, ToReferenceFrame(),
   1.582 +                                 aBuilder->GetBackgroundPaintFlags());
   1.583 +  painter.PaintRow(static_cast<nsTableRowFrame*>(mFrame));
   1.584 +}
   1.585 +
   1.586 +void
   1.587 +nsTableRowFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
   1.588 +                                  const nsRect&           aDirtyRect,
   1.589 +                                  const nsDisplayListSet& aLists)
   1.590 +{
   1.591 +  nsDisplayTableItem* item = nullptr;
   1.592 +  if (IsVisibleInSelection(aBuilder)) {
   1.593 +    bool isRoot = aBuilder->IsAtRootOfPseudoStackingContext();
   1.594 +    if (isRoot) {
   1.595 +      // This background is created regardless of whether this frame is
   1.596 +      // visible or not. Visibility decisions are delegated to the
   1.597 +      // table background painter.
   1.598 +      // We would use nsDisplayGeneric for this rare case except that we
   1.599 +      // need the background to be larger than the row frame in some
   1.600 +      // cases.
   1.601 +      item = new (aBuilder) nsDisplayTableRowBackground(aBuilder, this);
   1.602 +      aLists.BorderBackground()->AppendNewToTop(item);
   1.603 +    }
   1.604 +  }
   1.605 +  nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists, item);
   1.606 +}
   1.607 +
   1.608 +int
   1.609 +nsTableRowFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const
   1.610 +{
   1.611 +  int skip = 0;
   1.612 +  if (nullptr != GetPrevInFlow()) {
   1.613 +    skip |= LOGICAL_SIDE_B_START;
   1.614 +  }
   1.615 +  if (nullptr != GetNextInFlow()) {
   1.616 +    skip |= LOGICAL_SIDE_B_END;
   1.617 +  }
   1.618 +  return skip;
   1.619 +}
   1.620 +
   1.621 +// Calculate the cell's actual height given its pass2  height.
   1.622 +// Takes into account the specified height (in the style).
   1.623 +// Modifies the desired height that is passed in.
   1.624 +nsresult
   1.625 +nsTableRowFrame::CalculateCellActualHeight(nsTableCellFrame* aCellFrame,
   1.626 +                                           nscoord&          aDesiredHeight)
   1.627 +{
   1.628 +  nscoord specifiedHeight = 0;
   1.629 +  
   1.630 +  // Get the height specified in the style information
   1.631 +  const nsStylePosition* position = aCellFrame->StylePosition();
   1.632 +
   1.633 +  nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
   1.634 +  int32_t rowSpan = tableFrame->GetEffectiveRowSpan(*aCellFrame);
   1.635 +  
   1.636 +  switch (position->mHeight.GetUnit()) {
   1.637 +    case eStyleUnit_Calc: {
   1.638 +      if (position->mHeight.CalcHasPercent()) {
   1.639 +        // Treat this like "auto"
   1.640 +        break;
   1.641 +      }
   1.642 +      // Fall through to the coord case
   1.643 +    }
   1.644 +    case eStyleUnit_Coord: {
   1.645 +      nscoord outsideBoxSizing = 0;
   1.646 +      // In quirks mode, table cell width should be content-box, but height
   1.647 +      // should be border-box.
   1.648 +      // Because of this historic anomaly, we do not use quirk.css
   1.649 +      // (since we can't specify one value of box-sizing for width and another
   1.650 +      // for height)
   1.651 +      if (PresContext()->CompatibilityMode() != eCompatibility_NavQuirks) {
   1.652 +        switch (position->mBoxSizing) {
   1.653 +          case NS_STYLE_BOX_SIZING_CONTENT:
   1.654 +            outsideBoxSizing = aCellFrame->GetUsedBorderAndPadding().TopBottom();
   1.655 +            break;
   1.656 +          case NS_STYLE_BOX_SIZING_PADDING:
   1.657 +            outsideBoxSizing = aCellFrame->GetUsedBorder().TopBottom();
   1.658 +            break;
   1.659 +          default:
   1.660 +            // NS_STYLE_BOX_SIZING_BORDER
   1.661 +            break;
   1.662 +        }
   1.663 +      }
   1.664 +
   1.665 +      specifiedHeight =
   1.666 +        nsRuleNode::ComputeCoordPercentCalc(position->mHeight, 0) +
   1.667 +          outsideBoxSizing;
   1.668 +
   1.669 +      if (1 == rowSpan) 
   1.670 +        SetFixedHeight(specifiedHeight);
   1.671 +      break;
   1.672 +    }
   1.673 +    case eStyleUnit_Percent: {
   1.674 +      if (1 == rowSpan) 
   1.675 +        SetPctHeight(position->mHeight.GetPercentValue());
   1.676 +      // pct heights are handled when all of the cells are finished, so don't set specifiedHeight 
   1.677 +      break;
   1.678 +    }
   1.679 +    case eStyleUnit_Auto:
   1.680 +    default:
   1.681 +      break;
   1.682 +  }
   1.683 +
   1.684 +  // If the specified height is greater than the desired height, then use the specified height
   1.685 +  if (specifiedHeight > aDesiredHeight)
   1.686 +    aDesiredHeight = specifiedHeight;
   1.687 +
   1.688 +  return NS_OK;
   1.689 +}
   1.690 +
   1.691 +// Calculates the available width for the table cell based on the known
   1.692 +// column widths taking into account column spans and column spacing
   1.693 +static nscoord
   1.694 +CalcAvailWidth(nsTableFrame&     aTableFrame,
   1.695 +               nsTableCellFrame& aCellFrame,
   1.696 +               nscoord           aCellSpacingX)
   1.697 +{
   1.698 +  nscoord cellAvailWidth = 0;
   1.699 +  int32_t colIndex;
   1.700 +  aCellFrame.GetColIndex(colIndex);
   1.701 +  int32_t colspan = aTableFrame.GetEffectiveColSpan(aCellFrame);
   1.702 +  NS_ASSERTION(colspan > 0, "effective colspan should be positive");
   1.703 +
   1.704 +  for (int32_t spanX = 0; spanX < colspan; spanX++) {
   1.705 +    cellAvailWidth += aTableFrame.GetColumnWidth(colIndex + spanX);
   1.706 +    if (spanX > 0 &&
   1.707 +        aTableFrame.ColumnHasCellSpacingBefore(colIndex + spanX)) {
   1.708 +      cellAvailWidth += aCellSpacingX;
   1.709 +    }
   1.710 +  }
   1.711 +  return cellAvailWidth;
   1.712 +}
   1.713 +
   1.714 +nscoord
   1.715 +GetSpaceBetween(int32_t       aPrevColIndex,
   1.716 +                int32_t       aColIndex,
   1.717 +                int32_t       aColSpan,
   1.718 +                nsTableFrame& aTableFrame,
   1.719 +                nscoord       aCellSpacingX,
   1.720 +                bool          aIsLeftToRight,
   1.721 +                bool          aCheckVisibility)
   1.722 +{
   1.723 +  nscoord space = 0;
   1.724 +  int32_t colX;
   1.725 +  if (aIsLeftToRight) {
   1.726 +    for (colX = aPrevColIndex + 1; aColIndex > colX; colX++) {
   1.727 +      bool isCollapsed = false;
   1.728 +      if (!aCheckVisibility) {
   1.729 +        space += aTableFrame.GetColumnWidth(colX);
   1.730 +      }
   1.731 +      else {
   1.732 +        nsTableColFrame* colFrame = aTableFrame.GetColFrame(colX);
   1.733 +        const nsStyleVisibility* colVis = colFrame->StyleVisibility();
   1.734 +        bool collapseCol = (NS_STYLE_VISIBILITY_COLLAPSE == colVis->mVisible);
   1.735 +        nsIFrame* cgFrame = colFrame->GetParent();
   1.736 +        const nsStyleVisibility* groupVis = cgFrame->StyleVisibility();
   1.737 +        bool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE ==
   1.738 +                                groupVis->mVisible);
   1.739 +        isCollapsed = collapseCol || collapseGroup;
   1.740 +        if (!isCollapsed)
   1.741 +          space += aTableFrame.GetColumnWidth(colX);
   1.742 +      }
   1.743 +      if (!isCollapsed && aTableFrame.ColumnHasCellSpacingBefore(colX)) {
   1.744 +        space += aCellSpacingX;
   1.745 +      }
   1.746 +    }
   1.747 +  } 
   1.748 +  else {
   1.749 +    int32_t lastCol = aColIndex + aColSpan - 1;
   1.750 +    for (colX = aPrevColIndex - 1; colX > lastCol; colX--) {
   1.751 +      bool isCollapsed = false;
   1.752 +      if (!aCheckVisibility) {
   1.753 +        space += aTableFrame.GetColumnWidth(colX);
   1.754 +      }
   1.755 +      else {
   1.756 +        nsTableColFrame* colFrame = aTableFrame.GetColFrame(colX);
   1.757 +        const nsStyleVisibility* colVis = colFrame->StyleVisibility();
   1.758 +        bool collapseCol = (NS_STYLE_VISIBILITY_COLLAPSE == colVis->mVisible);
   1.759 +        nsIFrame* cgFrame = colFrame->GetParent();
   1.760 +        const nsStyleVisibility* groupVis = cgFrame->StyleVisibility();
   1.761 +        bool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE ==
   1.762 +                                groupVis->mVisible);
   1.763 +        isCollapsed = collapseCol || collapseGroup;
   1.764 +        if (!isCollapsed)
   1.765 +          space += aTableFrame.GetColumnWidth(colX);
   1.766 +      }
   1.767 +      if (!isCollapsed && aTableFrame.ColumnHasCellSpacingBefore(colX)) {
   1.768 +        space += aCellSpacingX;
   1.769 +      }
   1.770 +    }
   1.771 +  }
   1.772 +  return space;
   1.773 +}
   1.774 +
   1.775 +// subtract the heights of aRow's prev in flows from the unpaginated height
   1.776 +static
   1.777 +nscoord CalcHeightFromUnpaginatedHeight(nsPresContext*   aPresContext,
   1.778 +                                        nsTableRowFrame& aRow)
   1.779 +{
   1.780 +  nscoord height = 0;
   1.781 +  nsTableRowFrame* firstInFlow =
   1.782 +    static_cast<nsTableRowFrame*>(aRow.FirstInFlow());
   1.783 +  if (firstInFlow->HasUnpaginatedHeight()) {
   1.784 +    height = firstInFlow->GetUnpaginatedHeight(aPresContext);
   1.785 +    for (nsIFrame* prevInFlow = aRow.GetPrevInFlow(); prevInFlow;
   1.786 +         prevInFlow = prevInFlow->GetPrevInFlow()) {
   1.787 +      height -= prevInFlow->GetSize().height;
   1.788 +    }
   1.789 +  }
   1.790 +  return std::max(height, 0);
   1.791 +}
   1.792 +
   1.793 +nsresult
   1.794 +nsTableRowFrame::ReflowChildren(nsPresContext*          aPresContext,
   1.795 +                                nsHTMLReflowMetrics&     aDesiredSize,
   1.796 +                                const nsHTMLReflowState& aReflowState,
   1.797 +                                nsTableFrame&            aTableFrame,
   1.798 +                                nsReflowStatus&          aStatus)
   1.799 +{
   1.800 +  aStatus = NS_FRAME_COMPLETE;
   1.801 +
   1.802 +  // XXXldb Should we be checking constrained height instead?
   1.803 +  const bool isPaginated = aPresContext->IsPaginated();
   1.804 +  const bool borderCollapse = aTableFrame.IsBorderCollapse();
   1.805 +  nsresult rv = NS_OK;
   1.806 +  nscoord cellSpacingX = aTableFrame.GetCellSpacingX();
   1.807 +  int32_t cellColSpan = 1;  // must be defined here so it's set properly for non-cell kids
   1.808 +  
   1.809 +  nsTableIterator iter(*this);
   1.810 +  // remember the col index of the previous cell to handle rowspans into this row
   1.811 +  int32_t firstPrevColIndex = (iter.IsLeftToRight()) ? -1 : aTableFrame.GetColCount();
   1.812 +  int32_t prevColIndex  = firstPrevColIndex;
   1.813 +  nscoord x = 0; // running total of children x offset
   1.814 +
   1.815 +  // This computes the max of all cell heights
   1.816 +  nscoord cellMaxHeight = 0;
   1.817 +
   1.818 +  // Reflow each of our existing cell frames
   1.819 +  for (nsIFrame* kidFrame = iter.First(); kidFrame; kidFrame = iter.Next()) {
   1.820 +    nsTableCellFrame *cellFrame = do_QueryFrame(kidFrame);
   1.821 +    if (!cellFrame) {
   1.822 +      // XXXldb nsCSSFrameConstructor needs to enforce this!
   1.823 +      NS_NOTREACHED("yikes, a non-row child");
   1.824 +
   1.825 +      // it's an unknown frame type, give it a generic reflow and ignore the results
   1.826 +      nsTableCellReflowState kidReflowState(aPresContext, aReflowState,
   1.827 +                                            kidFrame, nsSize(0,0),
   1.828 +                                            nsHTMLReflowState::CALLER_WILL_INIT);
   1.829 +      InitChildReflowState(*aPresContext, nsSize(0,0), false, kidReflowState);
   1.830 +      nsHTMLReflowMetrics desiredSize(aReflowState);
   1.831 +      nsReflowStatus  status;
   1.832 +      ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, 0, 0, 0, status);
   1.833 +      kidFrame->DidReflow(aPresContext, nullptr, nsDidReflowStatus::FINISHED);
   1.834 +
   1.835 +      continue;
   1.836 +    }
   1.837 +
   1.838 +    // See if we should only reflow the dirty child frames
   1.839 +    bool doReflowChild = true;
   1.840 +    if (!aReflowState.ShouldReflowAllKids() &&
   1.841 +        !aTableFrame.IsGeometryDirty() &&
   1.842 +        !NS_SUBTREE_DIRTY(kidFrame)) {
   1.843 +      if (!aReflowState.mFlags.mSpecialHeightReflow)
   1.844 +        doReflowChild = false;
   1.845 +    }
   1.846 +    else if ((NS_UNCONSTRAINEDSIZE != aReflowState.AvailableHeight())) {
   1.847 +      // We don't reflow a rowspan >1 cell here with a constrained height. 
   1.848 +      // That happens in nsTableRowGroupFrame::SplitSpanningCells.
   1.849 +      if (aTableFrame.GetEffectiveRowSpan(*cellFrame) > 1) {
   1.850 +        doReflowChild = false;
   1.851 +      }
   1.852 +    }
   1.853 +    if (aReflowState.mFlags.mSpecialHeightReflow) {
   1.854 +      if (!isPaginated && !(cellFrame->GetStateBits() &
   1.855 +                            NS_FRAME_CONTAINS_RELATIVE_HEIGHT)) {
   1.856 +        continue;
   1.857 +      }
   1.858 +    }
   1.859 +
   1.860 +    int32_t cellColIndex;
   1.861 +    cellFrame->GetColIndex(cellColIndex);
   1.862 +    cellColSpan = aTableFrame.GetEffectiveColSpan(*cellFrame);
   1.863 +
   1.864 +    // If the adjacent cell is in a prior row (because of a rowspan) add in the space
   1.865 +    if ((iter.IsLeftToRight() && (prevColIndex != (cellColIndex - 1))) ||
   1.866 +        (!iter.IsLeftToRight() && (prevColIndex != cellColIndex + cellColSpan))) {
   1.867 +      x += GetSpaceBetween(prevColIndex, cellColIndex, cellColSpan, aTableFrame, 
   1.868 +                           cellSpacingX, iter.IsLeftToRight(), false);
   1.869 +    }
   1.870 +
   1.871 +    // remember the rightmost (ltr) or leftmost (rtl) column this cell spans into
   1.872 +    prevColIndex = (iter.IsLeftToRight()) ? cellColIndex + (cellColSpan - 1) : cellColIndex;
   1.873 +
   1.874 +    // Reflow the child frame
   1.875 +    nsRect kidRect = kidFrame->GetRect();
   1.876 +    nsRect kidVisualOverflow = kidFrame->GetVisualOverflowRect();
   1.877 +    bool firstReflow =
   1.878 +      (kidFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
   1.879 +
   1.880 +    if (doReflowChild) {
   1.881 +      // Calculate the available width for the table cell using the known column widths
   1.882 +      nscoord availCellWidth =
   1.883 +        CalcAvailWidth(aTableFrame, *cellFrame, cellSpacingX);
   1.884 +
   1.885 +      nsHTMLReflowMetrics desiredSize(aReflowState);
   1.886 +
   1.887 +      // If the avail width is not the same as last time we reflowed the cell or
   1.888 +      // the cell wants to be bigger than what was available last time or
   1.889 +      // it is a style change reflow or we are printing, then we must reflow the
   1.890 +      // cell. Otherwise we can skip the reflow.
   1.891 +      // XXXldb Why is this condition distinct from doReflowChild above?
   1.892 +      nsSize cellDesiredSize = cellFrame->GetDesiredSize();
   1.893 +      if ((availCellWidth != cellFrame->GetPriorAvailWidth())       ||
   1.894 +          (cellDesiredSize.width > cellFrame->GetPriorAvailWidth()) ||
   1.895 +          (GetStateBits() & NS_FRAME_IS_DIRTY)                      ||
   1.896 +          isPaginated                                               ||
   1.897 +          NS_SUBTREE_DIRTY(cellFrame)                               ||
   1.898 +          // See if it needs a special reflow, or if it had one that we need to undo.
   1.899 +          (cellFrame->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT) ||
   1.900 +          HasPctHeight()) {
   1.901 +        // Reflow the cell to fit the available width, height
   1.902 +        // XXX The old IR_ChildIsDirty code used availCellWidth here.
   1.903 +        nsSize  kidAvailSize(availCellWidth, aReflowState.AvailableHeight());
   1.904 +
   1.905 +        // Reflow the child
   1.906 +        nsTableCellReflowState kidReflowState(aPresContext, aReflowState, 
   1.907 +                                              kidFrame, kidAvailSize,
   1.908 +                                              nsHTMLReflowState::CALLER_WILL_INIT);
   1.909 +        InitChildReflowState(*aPresContext, kidAvailSize, borderCollapse,
   1.910 +                             kidReflowState);
   1.911 +
   1.912 +        nsReflowStatus status;
   1.913 +        rv = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState,
   1.914 +                         x, 0, 0, status);
   1.915 +
   1.916 +        // allow the table to determine if/how the table needs to be rebalanced
   1.917 +        // If any of the cells are not complete, then we're not complete
   1.918 +        if (NS_FRAME_IS_NOT_COMPLETE(status)) {
   1.919 +          aStatus = NS_FRAME_NOT_COMPLETE;
   1.920 +        }
   1.921 +      }
   1.922 +      else {
   1.923 +        if (x != kidRect.x) {
   1.924 +          kidFrame->InvalidateFrameSubtree();
   1.925 +        }
   1.926 +        
   1.927 +        desiredSize.Width() = cellDesiredSize.width;
   1.928 +        desiredSize.Height() = cellDesiredSize.height;
   1.929 +        desiredSize.mOverflowAreas = cellFrame->GetOverflowAreas();
   1.930 +
   1.931 +        // if we are in a floated table, our position is not yet established, so we cannot reposition our views
   1.932 +        // the containing block will do this for us after positioning the table
   1.933 +        if (!aTableFrame.IsFloating()) {
   1.934 +          // Because we may have moved the frame we need to make sure any views are
   1.935 +          // positioned properly. We have to do this, because any one of our parent
   1.936 +          // frames could have moved and we have no way of knowing...
   1.937 +          nsTableFrame::RePositionViews(kidFrame);
   1.938 +        }
   1.939 +      }
   1.940 +      
   1.941 +      if (NS_UNCONSTRAINEDSIZE == aReflowState.AvailableHeight()) {
   1.942 +        if (!GetPrevInFlow()) {
   1.943 +          // Calculate the cell's actual height given its pass2 height. This
   1.944 +          // function takes into account the specified height (in the style)
   1.945 +          CalculateCellActualHeight(cellFrame, desiredSize.Height());
   1.946 +        }
   1.947 +        // height may have changed, adjust descent to absorb any excess difference
   1.948 +        nscoord ascent;
   1.949 +        if (!kidFrame->GetFirstPrincipalChild()->GetFirstPrincipalChild())
   1.950 +          ascent = desiredSize.Height();
   1.951 +        else
   1.952 +          ascent = ((nsTableCellFrame *)kidFrame)->GetCellBaseline();
   1.953 +        nscoord descent = desiredSize.Height() - ascent;
   1.954 +        UpdateHeight(desiredSize.Height(), ascent, descent, &aTableFrame, cellFrame);
   1.955 +      }
   1.956 +      else {
   1.957 +        cellMaxHeight = std::max(cellMaxHeight, desiredSize.Height());
   1.958 +        int32_t rowSpan = aTableFrame.GetEffectiveRowSpan((nsTableCellFrame&)*kidFrame);
   1.959 +        if (1 == rowSpan) {
   1.960 +          SetContentHeight(cellMaxHeight);
   1.961 +        }
   1.962 +      }
   1.963 +
   1.964 +      // Place the child
   1.965 +      desiredSize.Width() = availCellWidth;
   1.966 +
   1.967 +      FinishReflowChild(kidFrame, aPresContext, desiredSize, nullptr, x, 0, 0);
   1.968 +
   1.969 +      nsTableFrame::InvalidateTableFrame(kidFrame, kidRect, kidVisualOverflow,
   1.970 +                                         firstReflow);
   1.971 +      
   1.972 +      x += desiredSize.Width();  
   1.973 +    }
   1.974 +    else {
   1.975 +      if (kidRect.x != x) {
   1.976 +        // Invalidate the old position
   1.977 +        kidFrame->InvalidateFrameSubtree();
   1.978 +        // move to the new position
   1.979 +        kidFrame->SetPosition(nsPoint(x, kidRect.y));
   1.980 +        nsTableFrame::RePositionViews(kidFrame);
   1.981 +        // invalidate the new position
   1.982 +        kidFrame->InvalidateFrameSubtree();
   1.983 +      }
   1.984 +      // we need to account for the cell's width even if it isn't reflowed
   1.985 +      x += kidRect.width;
   1.986 +
   1.987 +      if (kidFrame->GetNextInFlow()) {
   1.988 +        aStatus = NS_FRAME_NOT_COMPLETE;
   1.989 +      }
   1.990 +    }
   1.991 +    ConsiderChildOverflow(aDesiredSize.mOverflowAreas, kidFrame);
   1.992 +    x += cellSpacingX;
   1.993 +  }
   1.994 +
   1.995 +  // just set our width to what was available. The table will calculate the width and not use our value.
   1.996 +  aDesiredSize.Width() = aReflowState.AvailableWidth();
   1.997 +
   1.998 +  if (aReflowState.mFlags.mSpecialHeightReflow) {
   1.999 +    aDesiredSize.Height() = mRect.height;
  1.1000 +  }
  1.1001 +  else if (NS_UNCONSTRAINEDSIZE == aReflowState.AvailableHeight()) {
  1.1002 +    aDesiredSize.Height() = CalcHeight(aReflowState);
  1.1003 +    if (GetPrevInFlow()) {
  1.1004 +      nscoord height = CalcHeightFromUnpaginatedHeight(aPresContext, *this);
  1.1005 +      aDesiredSize.Height() = std::max(aDesiredSize.Height(), height);
  1.1006 +    }
  1.1007 +    else {
  1.1008 +      if (isPaginated && HasStyleHeight()) {
  1.1009 +        // set the unpaginated height so next in flows can try to honor it
  1.1010 +        SetHasUnpaginatedHeight(true);
  1.1011 +        SetUnpaginatedHeight(aPresContext, aDesiredSize.Height());
  1.1012 +      }
  1.1013 +      if (isPaginated && HasUnpaginatedHeight()) {
  1.1014 +        aDesiredSize.Height() = std::max(aDesiredSize.Height(), GetUnpaginatedHeight(aPresContext));
  1.1015 +      }
  1.1016 +    }
  1.1017 +  }
  1.1018 +  else { // constrained height, paginated
  1.1019 +    // Compute the height we should have from style (subtracting the
  1.1020 +    // height from our prev-in-flows from the style height)
  1.1021 +    nscoord styleHeight = CalcHeightFromUnpaginatedHeight(aPresContext, *this);
  1.1022 +    if (styleHeight > aReflowState.AvailableHeight()) {
  1.1023 +      styleHeight = aReflowState.AvailableHeight();
  1.1024 +      NS_FRAME_SET_INCOMPLETE(aStatus);
  1.1025 +    }
  1.1026 +    aDesiredSize.Height() = std::max(cellMaxHeight, styleHeight);
  1.1027 +  }
  1.1028 +  aDesiredSize.UnionOverflowAreasWithDesiredBounds();
  1.1029 +  FinishAndStoreOverflow(&aDesiredSize);
  1.1030 +  return rv;
  1.1031 +}
  1.1032 +
  1.1033 +/** Layout the entire row.
  1.1034 +  * This method stacks cells horizontally according to HTML 4.0 rules.
  1.1035 +  */
  1.1036 +nsresult
  1.1037 +nsTableRowFrame::Reflow(nsPresContext*          aPresContext,
  1.1038 +                        nsHTMLReflowMetrics&     aDesiredSize,
  1.1039 +                        const nsHTMLReflowState& aReflowState,
  1.1040 +                        nsReflowStatus&          aStatus)
  1.1041 +{
  1.1042 +  DO_GLOBAL_REFLOW_COUNT("nsTableRowFrame");
  1.1043 +  DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
  1.1044 +  nsresult rv = NS_OK;
  1.1045 +
  1.1046 +  nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
  1.1047 +  const nsStyleVisibility* rowVis = StyleVisibility();
  1.1048 +  bool collapseRow = (NS_STYLE_VISIBILITY_COLLAPSE == rowVis->mVisible);
  1.1049 +  if (collapseRow) {
  1.1050 +    tableFrame->SetNeedToCollapse(true);
  1.1051 +  }
  1.1052 +
  1.1053 +  // see if a special height reflow needs to occur due to having a pct height
  1.1054 +  nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState);
  1.1055 +
  1.1056 +  // See if we have a cell with specified/pct height
  1.1057 +  InitHasCellWithStyleHeight(tableFrame);
  1.1058 +
  1.1059 +  rv = ReflowChildren(aPresContext, aDesiredSize, aReflowState, *tableFrame,
  1.1060 +                      aStatus);
  1.1061 +
  1.1062 +  if (aPresContext->IsPaginated() && !NS_FRAME_IS_FULLY_COMPLETE(aStatus) &&
  1.1063 +      ShouldAvoidBreakInside(aReflowState)) {
  1.1064 +    aStatus = NS_INLINE_LINE_BREAK_BEFORE();
  1.1065 +  }
  1.1066 +
  1.1067 +  // just set our width to what was available. The table will calculate the width and not use our value.
  1.1068 +  aDesiredSize.Width() = aReflowState.AvailableWidth();
  1.1069 +
  1.1070 +  // If our parent is in initial reflow, it'll handle invalidating our
  1.1071 +  // entire overflow rect.
  1.1072 +  if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW) &&
  1.1073 +      nsSize(aDesiredSize.Width(), aDesiredSize.Height()) != mRect.Size()) {
  1.1074 +    InvalidateFrame();
  1.1075 +  }
  1.1076 +
  1.1077 +  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
  1.1078 +  return rv;
  1.1079 +}
  1.1080 +
  1.1081 +/**
  1.1082 + * This function is called by the row group frame's SplitRowGroup() code when
  1.1083 + * pushing a row frame that has cell frames that span into it. The cell frame
  1.1084 + * should be reflowed with the specified height
  1.1085 + */
  1.1086 +nscoord 
  1.1087 +nsTableRowFrame::ReflowCellFrame(nsPresContext*          aPresContext,
  1.1088 +                                 const nsHTMLReflowState& aReflowState,
  1.1089 +                                 bool                     aIsTopOfPage,
  1.1090 +                                 nsTableCellFrame*        aCellFrame,
  1.1091 +                                 nscoord                  aAvailableHeight,
  1.1092 +                                 nsReflowStatus&          aStatus)
  1.1093 +{
  1.1094 +  // Reflow the cell frame with the specified height. Use the existing width
  1.1095 +  nsRect cellRect = aCellFrame->GetRect();
  1.1096 +  nsRect cellVisualOverflow = aCellFrame->GetVisualOverflowRect();
  1.1097 +  
  1.1098 +  nsSize availSize(cellRect.width, aAvailableHeight);
  1.1099 +  nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
  1.1100 +  bool borderCollapse = tableFrame->IsBorderCollapse();
  1.1101 +  nsTableCellReflowState cellReflowState(aPresContext, aReflowState,
  1.1102 +                                         aCellFrame, availSize,
  1.1103 +                                         nsHTMLReflowState::CALLER_WILL_INIT);
  1.1104 +  InitChildReflowState(*aPresContext, availSize, borderCollapse, cellReflowState);
  1.1105 +  cellReflowState.mFlags.mIsTopOfPage = aIsTopOfPage;
  1.1106 +
  1.1107 +  nsHTMLReflowMetrics desiredSize(aReflowState);
  1.1108 +
  1.1109 +  ReflowChild(aCellFrame, aPresContext, desiredSize, cellReflowState,
  1.1110 +              0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus);
  1.1111 +  bool fullyComplete = NS_FRAME_IS_COMPLETE(aStatus) && !NS_FRAME_IS_TRUNCATED(aStatus);
  1.1112 +  if (fullyComplete) {
  1.1113 +    desiredSize.Height() = aAvailableHeight;
  1.1114 +  }
  1.1115 +  aCellFrame->SetSize(nsSize(cellRect.width, desiredSize.Height()));
  1.1116 +
  1.1117 +  // Note: VerticallyAlignChild can affect the overflow rect.
  1.1118 +  // XXX What happens if this cell has 'vertical-align: baseline' ?
  1.1119 +  // XXX Why is it assumed that the cell's ascent hasn't changed ?
  1.1120 +  if (fullyComplete) {
  1.1121 +    aCellFrame->VerticallyAlignChild(mMaxCellAscent);
  1.1122 +  }
  1.1123 +  
  1.1124 +  nsTableFrame::InvalidateTableFrame(aCellFrame, cellRect,
  1.1125 +                                     cellVisualOverflow,
  1.1126 +                                     (aCellFrame->GetStateBits() &
  1.1127 +                                      NS_FRAME_FIRST_REFLOW) != 0);
  1.1128 +  
  1.1129 +  aCellFrame->DidReflow(aPresContext, nullptr, nsDidReflowStatus::FINISHED);
  1.1130 +
  1.1131 +  return desiredSize.Height();
  1.1132 +}
  1.1133 +
  1.1134 +nscoord
  1.1135 +nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset,
  1.1136 +                                        nscoord aWidth,
  1.1137 +                                        bool    aCollapseGroup,
  1.1138 +                                        bool& aDidCollapse)
  1.1139 +{
  1.1140 +  const nsStyleVisibility* rowVis = StyleVisibility();
  1.1141 +  bool collapseRow = (NS_STYLE_VISIBILITY_COLLAPSE == rowVis->mVisible);
  1.1142 +  nsTableFrame* tableFrame = static_cast<nsTableFrame*>(
  1.1143 +    nsTableFrame::GetTableFrame(this)->FirstInFlow());
  1.1144 +  if (collapseRow) {
  1.1145 +    tableFrame->SetNeedToCollapse(true);
  1.1146 +  }
  1.1147 +
  1.1148 +  if (aRowOffset != 0) {
  1.1149 +    // We're moving, so invalidate our old position
  1.1150 +    InvalidateFrameSubtree();
  1.1151 +  }
  1.1152 +  
  1.1153 +  nsRect rowRect = GetRect();
  1.1154 +  nsRect oldRect = rowRect;
  1.1155 +  nsRect oldVisualOverflow = GetVisualOverflowRect();
  1.1156 +  
  1.1157 +  rowRect.y -= aRowOffset;
  1.1158 +  rowRect.width  = aWidth;
  1.1159 +  nsOverflowAreas overflow;
  1.1160 +  nscoord shift = 0;
  1.1161 +  nscoord cellSpacingX = tableFrame->GetCellSpacingX();
  1.1162 +  nscoord cellSpacingY = tableFrame->GetCellSpacingY();
  1.1163 +
  1.1164 +  if (aCollapseGroup || collapseRow) {
  1.1165 +    nsTableCellFrame* cellFrame = GetFirstCell();
  1.1166 +    aDidCollapse = true;
  1.1167 +    shift = rowRect.height + cellSpacingY;
  1.1168 +    while (cellFrame) {
  1.1169 +      nsRect cRect = cellFrame->GetRect();
  1.1170 +      // If aRowOffset != 0, there's no point in invalidating the cells, since
  1.1171 +      // we've already invalidated our overflow area.  Note that we _do_ still
  1.1172 +      // need to invalidate if our row is not moving, because the cell might
  1.1173 +      // span out of this row, so invalidating our row rect won't do enough.
  1.1174 +      if (aRowOffset == 0) {
  1.1175 +        InvalidateFrame();
  1.1176 +      }
  1.1177 +      cRect.height = 0;
  1.1178 +      cellFrame->SetRect(cRect);
  1.1179 +      cellFrame = cellFrame->GetNextCell();
  1.1180 +    }
  1.1181 +    rowRect.height = 0;
  1.1182 +  }
  1.1183 +  else { // row is not collapsed
  1.1184 +    nsTableIterator iter(*this);
  1.1185 +    // remember the col index of the previous cell to handle rowspans into this
  1.1186 +    // row
  1.1187 +    int32_t firstPrevColIndex = (iter.IsLeftToRight()) ? -1 :
  1.1188 +                                tableFrame->GetColCount();
  1.1189 +    int32_t prevColIndex  = firstPrevColIndex;
  1.1190 +    nscoord x = 0; // running total of children x offset
  1.1191 +
  1.1192 +    int32_t colIncrement = iter.IsLeftToRight() ? 1 : -1;
  1.1193 +
  1.1194 +    //nscoord x = cellSpacingX;
  1.1195 +
  1.1196 +    nsIFrame* kidFrame = iter.First();
  1.1197 +    while (kidFrame) {
  1.1198 +      nsTableCellFrame *cellFrame = do_QueryFrame(kidFrame);
  1.1199 +      if (cellFrame) {
  1.1200 +        int32_t cellColIndex;
  1.1201 +        cellFrame->GetColIndex(cellColIndex);
  1.1202 +        int32_t cellColSpan = tableFrame->GetEffectiveColSpan(*cellFrame);
  1.1203 +
  1.1204 +        // If the adjacent cell is in a prior row (because of a rowspan) add in
  1.1205 +        // the space
  1.1206 +        if ((iter.IsLeftToRight() && (prevColIndex != (cellColIndex - 1))) ||
  1.1207 +            (!iter.IsLeftToRight() &&
  1.1208 +             (prevColIndex != cellColIndex + cellColSpan))) {
  1.1209 +          x += GetSpaceBetween(prevColIndex, cellColIndex, cellColSpan,
  1.1210 +                               *tableFrame, cellSpacingX, iter.IsLeftToRight(),
  1.1211 +                               true);
  1.1212 +        }
  1.1213 +        nsRect cRect(x, 0, 0, rowRect.height);
  1.1214 +
  1.1215 +        // remember the rightmost (ltr) or leftmost (rtl) column this cell
  1.1216 +        // spans into
  1.1217 +        prevColIndex = (iter.IsLeftToRight()) ?
  1.1218 +                       cellColIndex + (cellColSpan - 1) : cellColIndex;
  1.1219 +        int32_t startIndex = (iter.IsLeftToRight()) ?
  1.1220 +                             cellColIndex : cellColIndex + (cellColSpan - 1);
  1.1221 +        int32_t actualColSpan = cellColSpan;
  1.1222 +        bool isVisible = false;
  1.1223 +        for (int32_t colX = startIndex; actualColSpan > 0;
  1.1224 +             colX += colIncrement, actualColSpan--) {
  1.1225 +
  1.1226 +          nsTableColFrame* colFrame = tableFrame->GetColFrame(colX);
  1.1227 +          const nsStyleVisibility* colVis = colFrame->StyleVisibility();
  1.1228 +          bool collapseCol = (NS_STYLE_VISIBILITY_COLLAPSE ==
  1.1229 +                                colVis->mVisible);
  1.1230 +          nsIFrame* cgFrame = colFrame->GetParent();
  1.1231 +          const nsStyleVisibility* groupVis = cgFrame->StyleVisibility();
  1.1232 +          bool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE ==
  1.1233 +                                  groupVis->mVisible);
  1.1234 +          bool isCollapsed = collapseCol || collapseGroup;
  1.1235 +          if (!isCollapsed) {
  1.1236 +            cRect.width += tableFrame->GetColumnWidth(colX);
  1.1237 +            isVisible = true;
  1.1238 +            if ((actualColSpan > 1)) {
  1.1239 +              nsTableColFrame* nextColFrame =
  1.1240 +                tableFrame->GetColFrame(colX + colIncrement);
  1.1241 +              const nsStyleVisibility* nextColVis =
  1.1242 +              nextColFrame->StyleVisibility();
  1.1243 +              if ( (NS_STYLE_VISIBILITY_COLLAPSE != nextColVis->mVisible) &&
  1.1244 +                  tableFrame->ColumnHasCellSpacingBefore(colX + colIncrement)) {
  1.1245 +                cRect.width += cellSpacingX;
  1.1246 +              }
  1.1247 +            }
  1.1248 +          }
  1.1249 +        }
  1.1250 +        x += cRect.width;
  1.1251 +        if (isVisible)
  1.1252 +          x += cellSpacingX;
  1.1253 +        int32_t actualRowSpan = tableFrame->GetEffectiveRowSpan(*cellFrame);
  1.1254 +        nsTableRowFrame* rowFrame = GetNextRow();
  1.1255 +        for (actualRowSpan--; actualRowSpan > 0 && rowFrame; actualRowSpan--) {
  1.1256 +          const nsStyleVisibility* nextRowVis = rowFrame->StyleVisibility();
  1.1257 +          bool collapseNextRow = (NS_STYLE_VISIBILITY_COLLAPSE ==
  1.1258 +                                    nextRowVis->mVisible);
  1.1259 +          if (!collapseNextRow) {
  1.1260 +            nsRect nextRect = rowFrame->GetRect();
  1.1261 +            cRect.height += nextRect.height + cellSpacingY;
  1.1262 +          }
  1.1263 +          rowFrame = rowFrame->GetNextRow();
  1.1264 +        }
  1.1265 +
  1.1266 +        nsRect oldCellRect = cellFrame->GetRect();
  1.1267 +        nsRect oldCellVisualOverflow = cellFrame->GetVisualOverflowRect();
  1.1268 +
  1.1269 +        if (aRowOffset == 0 && cRect.TopLeft() != oldCellRect.TopLeft()) {
  1.1270 +          // We're moving the cell.  Invalidate the old overflow area
  1.1271 +          cellFrame->InvalidateFrameSubtree();
  1.1272 +        }
  1.1273 +        
  1.1274 +        cellFrame->SetRect(cRect);
  1.1275 +
  1.1276 +        // XXXbz This looks completely bogus in the cases when we didn't
  1.1277 +        // collapse the cell!
  1.1278 +        nsRect cellBounds(0, 0, cRect.width, cRect.height);
  1.1279 +        nsOverflowAreas cellOverflow(cellBounds, cellBounds);
  1.1280 +        cellFrame->FinishAndStoreOverflow(cellOverflow, cRect.Size());
  1.1281 +        nsTableFrame::RePositionViews(cellFrame);
  1.1282 +        ConsiderChildOverflow(overflow, cellFrame);
  1.1283 +                
  1.1284 +        if (aRowOffset == 0) {
  1.1285 +          nsTableFrame::InvalidateTableFrame(cellFrame, oldCellRect,
  1.1286 +                                             oldCellVisualOverflow,
  1.1287 +                                             false);
  1.1288 +        }
  1.1289 +      }
  1.1290 +      kidFrame = iter.Next(); // Get the next child
  1.1291 +    }
  1.1292 +  }
  1.1293 +
  1.1294 +  SetRect(rowRect);
  1.1295 +  overflow.UnionAllWith(nsRect(0, 0, rowRect.width, rowRect.height));
  1.1296 +  FinishAndStoreOverflow(overflow, rowRect.Size());
  1.1297 +
  1.1298 +  nsTableFrame::RePositionViews(this);
  1.1299 +  nsTableFrame::InvalidateTableFrame(this, oldRect, oldVisualOverflow, false);
  1.1300 +  return shift;
  1.1301 +}
  1.1302 +
  1.1303 +/*
  1.1304 + * The following method is called by the row group frame's SplitRowGroup()
  1.1305 + * when it creates a continuing cell frame and wants to insert it into the
  1.1306 + * row's child list.
  1.1307 + */
  1.1308 +void 
  1.1309 +nsTableRowFrame::InsertCellFrame(nsTableCellFrame* aFrame,
  1.1310 +                                 int32_t           aColIndex)
  1.1311 +{
  1.1312 +  // Find the cell frame where col index < aColIndex
  1.1313 +  nsTableCellFrame* priorCell = nullptr;
  1.1314 +  for (nsIFrame* child = mFrames.FirstChild(); child;
  1.1315 +       child = child->GetNextSibling()) {
  1.1316 +    nsTableCellFrame *cellFrame = do_QueryFrame(child);
  1.1317 +    if (cellFrame) {
  1.1318 +      int32_t colIndex;
  1.1319 +      cellFrame->GetColIndex(colIndex);
  1.1320 +      if (colIndex < aColIndex) {
  1.1321 +        priorCell = cellFrame;
  1.1322 +      }
  1.1323 +      else break;
  1.1324 +    }
  1.1325 +  }
  1.1326 +  mFrames.InsertFrame(this, priorCell, aFrame);
  1.1327 +}
  1.1328 +
  1.1329 +nsIAtom*
  1.1330 +nsTableRowFrame::GetType() const
  1.1331 +{
  1.1332 +  return nsGkAtoms::tableRowFrame;
  1.1333 +}
  1.1334 +
  1.1335 +nsTableRowFrame*  
  1.1336 +nsTableRowFrame::GetNextRow() const
  1.1337 +{
  1.1338 +  nsIFrame* childFrame = GetNextSibling();
  1.1339 +  while (childFrame) {
  1.1340 +    nsTableRowFrame *rowFrame = do_QueryFrame(childFrame);
  1.1341 +    if (rowFrame) {
  1.1342 +	  NS_ASSERTION(NS_STYLE_DISPLAY_TABLE_ROW == childFrame->StyleDisplay()->mDisplay, "wrong display type on rowframe");
  1.1343 +      return rowFrame;
  1.1344 +    }
  1.1345 +    childFrame = childFrame->GetNextSibling();
  1.1346 +  }
  1.1347 +  return nullptr;
  1.1348 +}
  1.1349 +
  1.1350 +NS_DECLARE_FRAME_PROPERTY(RowUnpaginatedHeightProperty, nullptr)
  1.1351 +
  1.1352 +void 
  1.1353 +nsTableRowFrame::SetUnpaginatedHeight(nsPresContext* aPresContext,
  1.1354 +                                      nscoord        aValue)
  1.1355 +{
  1.1356 +  NS_ASSERTION(!GetPrevInFlow(), "program error");
  1.1357 +  // Get the property
  1.1358 +  aPresContext->PropertyTable()->
  1.1359 +    Set(this, RowUnpaginatedHeightProperty(), NS_INT32_TO_PTR(aValue));
  1.1360 +}
  1.1361 +
  1.1362 +nscoord
  1.1363 +nsTableRowFrame::GetUnpaginatedHeight(nsPresContext* aPresContext)
  1.1364 +{
  1.1365 +  FrameProperties props = FirstInFlow()->Properties();
  1.1366 +  return NS_PTR_TO_INT32(props.Get(RowUnpaginatedHeightProperty()));
  1.1367 +}
  1.1368 +
  1.1369 +void nsTableRowFrame::SetContinuousBCBorderWidth(uint8_t     aForSide,
  1.1370 +                                                 BCPixelSize aPixelValue)
  1.1371 +{
  1.1372 +  switch (aForSide) {
  1.1373 +    case NS_SIDE_RIGHT:
  1.1374 +      mRightContBorderWidth = aPixelValue;
  1.1375 +      return;
  1.1376 +    case NS_SIDE_TOP:
  1.1377 +      mTopContBorderWidth = aPixelValue;
  1.1378 +      return;
  1.1379 +    case NS_SIDE_LEFT:
  1.1380 +      mLeftContBorderWidth = aPixelValue;
  1.1381 +      return;
  1.1382 +    default:
  1.1383 +      NS_ERROR("invalid NS_SIDE arg");
  1.1384 +  }
  1.1385 +}
  1.1386 +#ifdef ACCESSIBILITY
  1.1387 +a11y::AccType
  1.1388 +nsTableRowFrame::AccessibleType()
  1.1389 +{
  1.1390 +  return a11y::eHTMLTableRowType;
  1.1391 +}
  1.1392 +#endif
  1.1393 +/**
  1.1394 + * Sets the NS_ROW_HAS_CELL_WITH_STYLE_HEIGHT bit to indicate whether
  1.1395 + * this row has any cells that have non-auto-height.  (Row-spanning
  1.1396 + * cells are ignored.)
  1.1397 + */
  1.1398 +void nsTableRowFrame::InitHasCellWithStyleHeight(nsTableFrame* aTableFrame)
  1.1399 +{
  1.1400 +  nsTableIterator iter(*this);
  1.1401 +
  1.1402 +  for (nsIFrame* kidFrame = iter.First(); kidFrame; kidFrame = iter.Next()) {
  1.1403 +    nsTableCellFrame *cellFrame = do_QueryFrame(kidFrame);
  1.1404 +    if (!cellFrame) {
  1.1405 +      NS_NOTREACHED("Table row has a non-cell child.");
  1.1406 +      continue;
  1.1407 +    }
  1.1408 +    // Ignore row-spanning cells
  1.1409 +    const nsStyleCoord &cellHeight = cellFrame->StylePosition()->mHeight;
  1.1410 +    if (aTableFrame->GetEffectiveRowSpan(*cellFrame) == 1 &&
  1.1411 +        cellHeight.GetUnit() != eStyleUnit_Auto &&
  1.1412 +         /* calc() with percentages treated like 'auto' */
  1.1413 +        (!cellHeight.IsCalcUnit() || !cellHeight.HasPercent())) {
  1.1414 +      AddStateBits(NS_ROW_HAS_CELL_WITH_STYLE_HEIGHT);
  1.1415 +      return;
  1.1416 +    }
  1.1417 +  }
  1.1418 +  RemoveStateBits(NS_ROW_HAS_CELL_WITH_STYLE_HEIGHT);
  1.1419 +}
  1.1420 +  
  1.1421 +void 
  1.1422 +nsTableRowFrame::InvalidateFrame(uint32_t aDisplayItemKey)
  1.1423 +{
  1.1424 +  nsIFrame::InvalidateFrame(aDisplayItemKey);
  1.1425 +  GetParent()->InvalidateFrameWithRect(GetVisualOverflowRect() + GetPosition(), aDisplayItemKey);
  1.1426 +}
  1.1427 +
  1.1428 +void
  1.1429 +nsTableRowFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
  1.1430 +{
  1.1431 +  nsIFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey);
  1.1432 +  // If we have filters applied that would affects our bounds, then
  1.1433 +  // we get an inactive layer created and this is computed
  1.1434 +  // within FrameLayerBuilder
  1.1435 +  GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey);
  1.1436 +}
  1.1437 +
  1.1438 +/* ----- global methods ----- */
  1.1439 +
  1.1440 +nsIFrame* 
  1.1441 +NS_NewTableRowFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
  1.1442 +{
  1.1443 +  return new (aPresShell) nsTableRowFrame(aContext);
  1.1444 +}
  1.1445 +
  1.1446 +NS_IMPL_FRAMEARENA_HELPERS(nsTableRowFrame)
  1.1447 +
  1.1448 +#ifdef DEBUG_FRAME_DUMP
  1.1449 +nsresult
  1.1450 +nsTableRowFrame::GetFrameName(nsAString& aResult) const
  1.1451 +{
  1.1452 +  return MakeFrameName(NS_LITERAL_STRING("TableRow"), aResult);
  1.1453 +}
  1.1454 +#endif

mercurial