layout/tables/nsTableCellFrame.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/tables/nsTableCellFrame.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1204 @@
     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 "nsTableFrame.h"
     1.9 +#include "nsTableColFrame.h"
    1.10 +#include "nsTableCellFrame.h"
    1.11 +#include "nsTableRowFrame.h"
    1.12 +#include "nsTableRowGroupFrame.h"
    1.13 +#include "nsTablePainter.h"
    1.14 +#include "nsStyleContext.h"
    1.15 +#include "nsStyleConsts.h"
    1.16 +#include "nsPresContext.h"
    1.17 +#include "nsRenderingContext.h"
    1.18 +#include "nsCSSRendering.h"
    1.19 +#include "nsIContent.h"
    1.20 +#include "nsGenericHTMLElement.h"
    1.21 +#include "nsAttrValueInlines.h"
    1.22 +#include "nsHTMLParts.h"
    1.23 +#include "nsGkAtoms.h"
    1.24 +#include "nsIPresShell.h"
    1.25 +#include "nsCOMPtr.h"
    1.26 +#include "nsIServiceManager.h"
    1.27 +#include "nsIDOMNode.h"
    1.28 +#include "nsNameSpaceManager.h"
    1.29 +#include "nsDisplayList.h"
    1.30 +#include "nsLayoutUtils.h"
    1.31 +#include "nsTextFrame.h"
    1.32 +#include "FrameLayerBuilder.h"
    1.33 +#include <algorithm>
    1.34 +
    1.35 +//TABLECELL SELECTION
    1.36 +#include "nsFrameSelection.h"
    1.37 +#include "mozilla/LookAndFeel.h"
    1.38 +
    1.39 +using namespace mozilla;
    1.40 +
    1.41 +
    1.42 +nsTableCellFrame::nsTableCellFrame(nsStyleContext* aContext) :
    1.43 +  nsContainerFrame(aContext)
    1.44 +{
    1.45 +  mColIndex = 0;
    1.46 +  mPriorAvailWidth = 0;
    1.47 +
    1.48 +  SetContentEmpty(false);
    1.49 +  SetHasPctOverHeight(false);
    1.50 +}
    1.51 +
    1.52 +nsTableCellFrame::~nsTableCellFrame()
    1.53 +{
    1.54 +}
    1.55 +
    1.56 +NS_IMPL_FRAMEARENA_HELPERS(nsTableCellFrame)
    1.57 +
    1.58 +nsTableCellFrame*
    1.59 +nsTableCellFrame::GetNextCell() const
    1.60 +{
    1.61 +  nsIFrame* childFrame = GetNextSibling();
    1.62 +  while (childFrame) {
    1.63 +    nsTableCellFrame *cellFrame = do_QueryFrame(childFrame);
    1.64 +    if (cellFrame) {
    1.65 +      return cellFrame;
    1.66 +    }
    1.67 +    childFrame = childFrame->GetNextSibling();
    1.68 +  }
    1.69 +  return nullptr;
    1.70 +}
    1.71 +
    1.72 +void
    1.73 +nsTableCellFrame::Init(nsIContent*      aContent,
    1.74 +                       nsIFrame*        aParent,
    1.75 +                       nsIFrame*        aPrevInFlow)
    1.76 +{
    1.77 +  // Let the base class do its initialization
    1.78 +  nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
    1.79 +
    1.80 +  if (GetStateBits() & NS_FRAME_FONT_INFLATION_CONTAINER) {
    1.81 +    AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT);
    1.82 +  }
    1.83 +
    1.84 +  if (aPrevInFlow) {
    1.85 +    // Set the column index
    1.86 +    nsTableCellFrame* cellFrame = (nsTableCellFrame*)aPrevInFlow;
    1.87 +    int32_t           colIndex;
    1.88 +    cellFrame->GetColIndex(colIndex);
    1.89 +    SetColIndex(colIndex);
    1.90 +  }
    1.91 +}
    1.92 +
    1.93 +void
    1.94 +nsTableCellFrame::DestroyFrom(nsIFrame* aDestructRoot)
    1.95 +{
    1.96 +  if (GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) {
    1.97 +    nsTableFrame::UnregisterPositionedTablePart(this, aDestructRoot);
    1.98 +  }
    1.99 +
   1.100 +  nsContainerFrame::DestroyFrom(aDestructRoot);
   1.101 +}
   1.102 +
   1.103 +// nsIPercentHeightObserver methods
   1.104 +
   1.105 +void
   1.106 +nsTableCellFrame::NotifyPercentHeight(const nsHTMLReflowState& aReflowState)
   1.107 +{
   1.108 +  // nsHTMLReflowState ensures the mCBReflowState of blocks inside a
   1.109 +  // cell is the cell frame, not the inner-cell block, and that the
   1.110 +  // containing block of an inner table is the containing block of its
   1.111 +  // outer table.
   1.112 +  // XXXldb Given the now-stricter |NeedsToObserve|, many if not all of
   1.113 +  // these tests are probably unnecessary.
   1.114 +
   1.115 +  // Maybe the cell reflow state; we sure if we're inside the |if|.
   1.116 +  const nsHTMLReflowState *cellRS = aReflowState.mCBReflowState;
   1.117 +
   1.118 +  if (cellRS && cellRS->frame == this &&
   1.119 +      (cellRS->ComputedHeight() == NS_UNCONSTRAINEDSIZE ||
   1.120 +       cellRS->ComputedHeight() == 0)) { // XXXldb Why 0?
   1.121 +    // This is a percentage height on a frame whose percentage heights
   1.122 +    // are based on the height of the cell, since its containing block
   1.123 +    // is the inner cell frame.
   1.124 +
   1.125 +    // We'll only honor the percent height if sibling-cells/ancestors
   1.126 +    // have specified/pct height. (Also, siblings only count for this if
   1.127 +    // both this cell and the sibling cell span exactly 1 row.)
   1.128 +
   1.129 +    if (nsTableFrame::AncestorsHaveStyleHeight(*cellRS) ||
   1.130 +        (nsTableFrame::GetTableFrame(this)->GetEffectiveRowSpan(*this) == 1 &&
   1.131 +         (cellRS->parentReflowState->frame->GetStateBits() &
   1.132 +          NS_ROW_HAS_CELL_WITH_STYLE_HEIGHT))) {
   1.133 +
   1.134 +      for (const nsHTMLReflowState *rs = aReflowState.parentReflowState;
   1.135 +           rs != cellRS;
   1.136 +           rs = rs->parentReflowState) {
   1.137 +        rs->frame->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT);
   1.138 +      }
   1.139 +
   1.140 +      nsTableFrame::RequestSpecialHeightReflow(*cellRS);
   1.141 +    }
   1.142 +  }
   1.143 +}
   1.144 +
   1.145 +// The cell needs to observe its block and things inside its block but nothing below that
   1.146 +bool
   1.147 +nsTableCellFrame::NeedsToObserve(const nsHTMLReflowState& aReflowState)
   1.148 +{
   1.149 +  const nsHTMLReflowState *rs = aReflowState.parentReflowState;
   1.150 +  if (!rs)
   1.151 +    return false;
   1.152 +  if (rs->frame == this) {
   1.153 +    // We always observe the child block.  It will never send any
   1.154 +    // notifications, but we need this so that the observer gets
   1.155 +    // propagated to its kids.
   1.156 +    return true;
   1.157 +  }
   1.158 +  rs = rs->parentReflowState;
   1.159 +  if (!rs) {
   1.160 +    return false;
   1.161 +  }
   1.162 +
   1.163 +  // We always need to let the percent height observer be propagated
   1.164 +  // from an outer table frame to an inner table frame.
   1.165 +  nsIAtom *fType = aReflowState.frame->GetType();
   1.166 +  if (fType == nsGkAtoms::tableFrame) {
   1.167 +    return true;
   1.168 +  }
   1.169 +
   1.170 +  // We need the observer to be propagated to all children of the cell
   1.171 +  // (i.e., children of the child block) in quirks mode, but only to
   1.172 +  // tables in standards mode.
   1.173 +  return rs->frame == this &&
   1.174 +         (PresContext()->CompatibilityMode() == eCompatibility_NavQuirks ||
   1.175 +          fType == nsGkAtoms::tableOuterFrame);
   1.176 +}
   1.177 +
   1.178 +nsresult
   1.179 +nsTableCellFrame::GetRowIndex(int32_t &aRowIndex) const
   1.180 +{
   1.181 +  nsresult result;
   1.182 +  nsTableRowFrame* row = static_cast<nsTableRowFrame*>(GetParent());
   1.183 +  if (row) {
   1.184 +    aRowIndex = row->GetRowIndex();
   1.185 +    result = NS_OK;
   1.186 +  }
   1.187 +  else {
   1.188 +    aRowIndex = 0;
   1.189 +    result = NS_ERROR_NOT_INITIALIZED;
   1.190 +  }
   1.191 +  return result;
   1.192 +}
   1.193 +
   1.194 +nsresult
   1.195 +nsTableCellFrame::GetColIndex(int32_t &aColIndex) const
   1.196 +{
   1.197 +  if (GetPrevInFlow()) {
   1.198 +    return static_cast<nsTableCellFrame*>(FirstInFlow())->GetColIndex(aColIndex);
   1.199 +  }
   1.200 +  else {
   1.201 +    aColIndex = mColIndex;
   1.202 +    return  NS_OK;
   1.203 +  }
   1.204 +}
   1.205 +
   1.206 +nsresult
   1.207 +nsTableCellFrame::AttributeChanged(int32_t         aNameSpaceID,
   1.208 +                                   nsIAtom*        aAttribute,
   1.209 +                                   int32_t         aModType)
   1.210 +{
   1.211 +  // We need to recalculate in this case because of the nowrap quirk in
   1.212 +  // BasicTableLayoutStrategy
   1.213 +  if (aNameSpaceID == kNameSpaceID_None && aAttribute == nsGkAtoms::nowrap &&
   1.214 +      PresContext()->CompatibilityMode() == eCompatibility_NavQuirks) {
   1.215 +    PresContext()->PresShell()->
   1.216 +      FrameNeedsReflow(this, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
   1.217 +  }
   1.218 +  // let the table frame decide what to do
   1.219 +  nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
   1.220 +  tableFrame->AttributeChangedFor(this, mContent, aAttribute);
   1.221 +  return NS_OK;
   1.222 +}
   1.223 +
   1.224 +/* virtual */ void
   1.225 +nsTableCellFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
   1.226 +{
   1.227 +  nsContainerFrame::DidSetStyleContext(aOldStyleContext);
   1.228 +
   1.229 +  if (!aOldStyleContext) //avoid this on init
   1.230 +    return;
   1.231 +
   1.232 +  nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
   1.233 +  if (tableFrame->IsBorderCollapse() &&
   1.234 +      tableFrame->BCRecalcNeeded(aOldStyleContext, StyleContext())) {
   1.235 +    int32_t colIndex, rowIndex;
   1.236 +    GetColIndex(colIndex);
   1.237 +    GetRowIndex(rowIndex);
   1.238 +    // row span needs to be clamped as we do not create rows in the cellmap
   1.239 +    // which do not have cells originating in them
   1.240 +    nsIntRect damageArea(colIndex, rowIndex, GetColSpan(),
   1.241 +      std::min(GetRowSpan(), tableFrame->GetRowCount() - rowIndex));
   1.242 +    tableFrame->AddBCDamageArea(damageArea);
   1.243 +  }
   1.244 +}
   1.245 +
   1.246 +
   1.247 +nsresult
   1.248 +nsTableCellFrame::AppendFrames(ChildListID     aListID,
   1.249 +                               nsFrameList&    aFrameList)
   1.250 +{
   1.251 +  NS_PRECONDITION(false, "unsupported operation");
   1.252 +  return NS_ERROR_NOT_IMPLEMENTED;
   1.253 +}
   1.254 +
   1.255 +nsresult
   1.256 +nsTableCellFrame::InsertFrames(ChildListID     aListID,
   1.257 +                               nsIFrame*       aPrevFrame,
   1.258 +                               nsFrameList&    aFrameList)
   1.259 +{
   1.260 +  NS_PRECONDITION(false, "unsupported operation");
   1.261 +  return NS_ERROR_NOT_IMPLEMENTED;
   1.262 +}
   1.263 +
   1.264 +nsresult
   1.265 +nsTableCellFrame::RemoveFrame(ChildListID     aListID,
   1.266 +                              nsIFrame*       aOldFrame)
   1.267 +{
   1.268 +  NS_PRECONDITION(false, "unsupported operation");
   1.269 +  return NS_ERROR_NOT_IMPLEMENTED;
   1.270 +}
   1.271 +
   1.272 +void nsTableCellFrame::SetColIndex(int32_t aColIndex)
   1.273 +{
   1.274 +  mColIndex = aColIndex;
   1.275 +}
   1.276 +
   1.277 +/* virtual */ nsMargin
   1.278 +nsTableCellFrame::GetUsedMargin() const
   1.279 +{
   1.280 +  return nsMargin(0,0,0,0);
   1.281 +}
   1.282 +
   1.283 +//ASSURE DIFFERENT COLORS for selection
   1.284 +inline nscolor EnsureDifferentColors(nscolor colorA, nscolor colorB)
   1.285 +{
   1.286 +    if (colorA == colorB)
   1.287 +    {
   1.288 +      nscolor res;
   1.289 +      res = NS_RGB(NS_GET_R(colorA) ^ 0xff,
   1.290 +                   NS_GET_G(colorA) ^ 0xff,
   1.291 +                   NS_GET_B(colorA) ^ 0xff);
   1.292 +      return res;
   1.293 +    }
   1.294 +    return colorA;
   1.295 +}
   1.296 +
   1.297 +void
   1.298 +nsTableCellFrame::DecorateForSelection(nsRenderingContext& aRenderingContext,
   1.299 +                                       nsPoint aPt)
   1.300 +{
   1.301 +  NS_ASSERTION(IsSelected(), "Should only be called for selected cells");
   1.302 +  int16_t displaySelection;
   1.303 +  nsPresContext* presContext = PresContext();
   1.304 +  displaySelection = DisplaySelection(presContext);
   1.305 +  if (displaySelection) {
   1.306 +    nsRefPtr<nsFrameSelection> frameSelection =
   1.307 +      presContext->PresShell()->FrameSelection();
   1.308 +
   1.309 +    if (frameSelection->GetTableCellSelection()) {
   1.310 +      nscolor       bordercolor;
   1.311 +      if (displaySelection == nsISelectionController::SELECTION_DISABLED) {
   1.312 +        bordercolor = NS_RGB(176,176,176);// disabled color
   1.313 +      }
   1.314 +      else {
   1.315 +        bordercolor =
   1.316 +          LookAndFeel::GetColor(LookAndFeel::eColorID_TextSelectBackground);
   1.317 +      }
   1.318 +      nscoord threePx = nsPresContext::CSSPixelsToAppUnits(3);
   1.319 +      if ((mRect.width > threePx) && (mRect.height > threePx))
   1.320 +      {
   1.321 +        //compare bordercolor to ((nsStyleColor *)myColor)->mBackgroundColor)
   1.322 +        bordercolor = EnsureDifferentColors(bordercolor,
   1.323 +                                            StyleBackground()->mBackgroundColor);
   1.324 +        nsRenderingContext::AutoPushTranslation
   1.325 +            translate(&aRenderingContext, aPt);
   1.326 +        nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
   1.327 +
   1.328 +        aRenderingContext.SetColor(bordercolor);
   1.329 +        aRenderingContext.DrawLine(onePixel, 0, mRect.width, 0);
   1.330 +        aRenderingContext.DrawLine(0, onePixel, 0, mRect.height);
   1.331 +        aRenderingContext.DrawLine(onePixel, mRect.height, mRect.width, mRect.height);
   1.332 +        aRenderingContext.DrawLine(mRect.width, onePixel, mRect.width, mRect.height);
   1.333 +        //middle
   1.334 +        aRenderingContext.DrawRect(onePixel, onePixel, mRect.width-onePixel,
   1.335 +                                   mRect.height-onePixel);
   1.336 +        //shading
   1.337 +        aRenderingContext.DrawLine(2*onePixel, mRect.height-2*onePixel,
   1.338 +                                   mRect.width-onePixel, mRect.height- (2*onePixel));
   1.339 +        aRenderingContext.DrawLine(mRect.width - (2*onePixel), 2*onePixel,
   1.340 +                                   mRect.width - (2*onePixel), mRect.height-onePixel);
   1.341 +      }
   1.342 +    }
   1.343 +  }
   1.344 +}
   1.345 +
   1.346 +void
   1.347 +nsTableCellFrame::PaintBackground(nsRenderingContext& aRenderingContext,
   1.348 +                                  const nsRect&        aDirtyRect,
   1.349 +                                  nsPoint              aPt,
   1.350 +                                  uint32_t             aFlags)
   1.351 +{
   1.352 +  nsRect rect(aPt, GetSize());
   1.353 +  nsCSSRendering::PaintBackground(PresContext(), aRenderingContext, this,
   1.354 +                                  aDirtyRect, rect, aFlags);
   1.355 +}
   1.356 +
   1.357 +// Called by nsTablePainter
   1.358 +void
   1.359 +nsTableCellFrame::PaintCellBackground(nsRenderingContext& aRenderingContext,
   1.360 +                                      const nsRect& aDirtyRect, nsPoint aPt,
   1.361 +                                      uint32_t aFlags)
   1.362 +{
   1.363 +  if (!StyleVisibility()->IsVisible())
   1.364 +    return;
   1.365 +
   1.366 +  PaintBackground(aRenderingContext, aDirtyRect, aPt, aFlags);
   1.367 +}
   1.368 +
   1.369 +nsresult
   1.370 +nsTableCellFrame::ProcessBorders(nsTableFrame* aFrame,
   1.371 +                                 nsDisplayListBuilder* aBuilder,
   1.372 +                                 const nsDisplayListSet& aLists)
   1.373 +{
   1.374 +  const nsStyleBorder* borderStyle = StyleBorder();
   1.375 +  if (aFrame->IsBorderCollapse() || !borderStyle->HasBorder())
   1.376 +    return NS_OK;
   1.377 +
   1.378 +  if (!GetContentEmpty() ||
   1.379 +      StyleTableBorder()->mEmptyCells == NS_STYLE_TABLE_EMPTY_CELLS_SHOW) {
   1.380 +    aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
   1.381 +                                              nsDisplayBorder(aBuilder, this));
   1.382 +  }
   1.383 +
   1.384 +  return NS_OK;
   1.385 +}
   1.386 +
   1.387 +class nsDisplayTableCellBackground : public nsDisplayTableItem {
   1.388 +public:
   1.389 +  nsDisplayTableCellBackground(nsDisplayListBuilder* aBuilder,
   1.390 +                               nsTableCellFrame* aFrame) :
   1.391 +    nsDisplayTableItem(aBuilder, aFrame) {
   1.392 +    MOZ_COUNT_CTOR(nsDisplayTableCellBackground);
   1.393 +  }
   1.394 +#ifdef NS_BUILD_REFCNT_LOGGING
   1.395 +  virtual ~nsDisplayTableCellBackground() {
   1.396 +    MOZ_COUNT_DTOR(nsDisplayTableCellBackground);
   1.397 +  }
   1.398 +#endif
   1.399 +
   1.400 +  virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
   1.401 +                       HitTestState* aState,
   1.402 +                       nsTArray<nsIFrame*> *aOutFrames) MOZ_OVERRIDE {
   1.403 +    aOutFrames->AppendElement(mFrame);
   1.404 +  }
   1.405 +  virtual void Paint(nsDisplayListBuilder* aBuilder,
   1.406 +                     nsRenderingContext* aCtx) MOZ_OVERRIDE;
   1.407 +  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
   1.408 +                           bool* aSnap) MOZ_OVERRIDE;
   1.409 +  virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
   1.410 +                                         const nsDisplayItemGeometry* aGeometry,
   1.411 +                                         nsRegion *aInvalidRegion) MOZ_OVERRIDE;
   1.412 +
   1.413 +  NS_DISPLAY_DECL_NAME("TableCellBackground", TYPE_TABLE_CELL_BACKGROUND)
   1.414 +};
   1.415 +
   1.416 +void nsDisplayTableCellBackground::Paint(nsDisplayListBuilder* aBuilder,
   1.417 +                                         nsRenderingContext* aCtx)
   1.418 +{
   1.419 +  static_cast<nsTableCellFrame*>(mFrame)->
   1.420 +    PaintBackground(*aCtx, mVisibleRect, ToReferenceFrame(),
   1.421 +                    aBuilder->GetBackgroundPaintFlags());
   1.422 +}
   1.423 +
   1.424 +nsRect
   1.425 +nsDisplayTableCellBackground::GetBounds(nsDisplayListBuilder* aBuilder,
   1.426 +                                        bool* aSnap)
   1.427 +{
   1.428 +  // revert from nsDisplayTableItem's implementation ... cell backgrounds
   1.429 +  // don't overflow the cell
   1.430 +  return nsDisplayItem::GetBounds(aBuilder, aSnap);
   1.431 +}
   1.432 +
   1.433 +void
   1.434 +nsDisplayTableCellBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
   1.435 +                                                        const nsDisplayItemGeometry* aGeometry,
   1.436 +                                                        nsRegion *aInvalidRegion)
   1.437 +{
   1.438 +  if (aBuilder->ShouldSyncDecodeImages()) {
   1.439 +    if (!nsCSSRendering::AreAllBackgroundImagesDecodedForFrame(mFrame)) {
   1.440 +      bool snap;
   1.441 +      aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
   1.442 +    }
   1.443 +  }
   1.444 +
   1.445 +  nsDisplayTableItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
   1.446 +}
   1.447 +
   1.448 +void nsTableCellFrame::InvalidateFrame(uint32_t aDisplayItemKey)
   1.449 +{
   1.450 +  nsIFrame::InvalidateFrame(aDisplayItemKey);
   1.451 +  GetParent()->InvalidateFrameWithRect(GetVisualOverflowRect() + GetPosition(), aDisplayItemKey);
   1.452 +}
   1.453 +
   1.454 +void nsTableCellFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
   1.455 +{
   1.456 +  nsIFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey);
   1.457 +  // If we have filters applied that would affects our bounds, then
   1.458 +  // we get an inactive layer created and this is computed
   1.459 +  // within FrameLayerBuilder
   1.460 +  GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey);
   1.461 +}
   1.462 +
   1.463 +static void
   1.464 +PaintTableCellSelection(nsIFrame* aFrame, nsRenderingContext* aCtx,
   1.465 +                        const nsRect& aRect, nsPoint aPt)
   1.466 +{
   1.467 +  static_cast<nsTableCellFrame*>(aFrame)->DecorateForSelection(*aCtx, aPt);
   1.468 +}
   1.469 +
   1.470 +void
   1.471 +nsTableCellFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
   1.472 +                                   const nsRect&           aDirtyRect,
   1.473 +                                   const nsDisplayListSet& aLists)
   1.474 +{
   1.475 +  DO_GLOBAL_REFLOW_COUNT_DSP("nsTableCellFrame");
   1.476 +  if (IsVisibleInSelection(aBuilder)) {
   1.477 +    nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
   1.478 +    int32_t emptyCellStyle = GetContentEmpty() && !tableFrame->IsBorderCollapse() ?
   1.479 +                                StyleTableBorder()->mEmptyCells
   1.480 +                                : NS_STYLE_TABLE_EMPTY_CELLS_SHOW;
   1.481 +    // take account of 'empty-cells'
   1.482 +    if (StyleVisibility()->IsVisible() &&
   1.483 +        (NS_STYLE_TABLE_EMPTY_CELLS_HIDE != emptyCellStyle)) {
   1.484 +    
   1.485 +    
   1.486 +      bool isRoot = aBuilder->IsAtRootOfPseudoStackingContext();
   1.487 +      if (!isRoot) {
   1.488 +        nsDisplayTableItem* currentItem = aBuilder->GetCurrentTableItem();
   1.489 +        if (currentItem) {
   1.490 +          currentItem->UpdateForFrameBackground(this);
   1.491 +        }
   1.492 +      }
   1.493 +    
   1.494 +      // display outset box-shadows if we need to.
   1.495 +      const nsStyleBorder* borderStyle = StyleBorder();
   1.496 +      bool hasBoxShadow = !!borderStyle->mBoxShadow;
   1.497 +      if (hasBoxShadow) {
   1.498 +        aLists.BorderBackground()->AppendNewToTop(
   1.499 +          new (aBuilder) nsDisplayBoxShadowOuter(aBuilder, this));
   1.500 +      }
   1.501 +    
   1.502 +      // display background if we need to.
   1.503 +      if (aBuilder->IsForEventDelivery() ||
   1.504 +          (((!tableFrame->IsBorderCollapse() || isRoot) &&
   1.505 +          (!StyleBackground()->IsTransparent() || StyleDisplay()->mAppearance)))) {
   1.506 +        // The cell background was not painted by the nsTablePainter,
   1.507 +        // so we need to do it. We have special background processing here
   1.508 +        // so we need to duplicate some code from nsFrame::DisplayBorderBackgroundOutline
   1.509 +        nsDisplayTableItem* item =
   1.510 +          new (aBuilder) nsDisplayTableCellBackground(aBuilder, this);
   1.511 +        aLists.BorderBackground()->AppendNewToTop(item);
   1.512 +        item->UpdateForFrameBackground(this);
   1.513 +      }
   1.514 +    
   1.515 +      // display inset box-shadows if we need to.
   1.516 +      if (hasBoxShadow) {
   1.517 +        aLists.BorderBackground()->AppendNewToTop(
   1.518 +          new (aBuilder) nsDisplayBoxShadowInner(aBuilder, this));
   1.519 +      }
   1.520 +    
   1.521 +      // display borders if we need to
   1.522 +      ProcessBorders(tableFrame, aBuilder, aLists);
   1.523 +    
   1.524 +      // and display the selection border if we need to
   1.525 +      if (IsSelected()) {
   1.526 +        aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
   1.527 +          nsDisplayGeneric(aBuilder, this, ::PaintTableCellSelection,
   1.528 +                           "TableCellSelection",
   1.529 +                           nsDisplayItem::TYPE_TABLE_CELL_SELECTION));
   1.530 +      }
   1.531 +    }
   1.532 +    
   1.533 +    // the 'empty-cells' property has no effect on 'outline'
   1.534 +    DisplayOutline(aBuilder, aLists);
   1.535 +  }
   1.536 +
   1.537 +  // Push a null 'current table item' so that descendant tables can't
   1.538 +  // accidentally mess with our table
   1.539 +  nsAutoPushCurrentTableItem pushTableItem;
   1.540 +  pushTableItem.Push(aBuilder, nullptr);
   1.541 +
   1.542 +  nsIFrame* kid = mFrames.FirstChild();
   1.543 +  NS_ASSERTION(kid && !kid->GetNextSibling(), "Table cells should have just one child");
   1.544 +  // The child's background will go in our BorderBackground() list.
   1.545 +  // This isn't a problem since it won't have a real background except for
   1.546 +  // event handling. We do not call BuildDisplayListForNonBlockChildren
   1.547 +  // because that/ would put the child's background in the Content() list
   1.548 +  // which isn't right (e.g., would end up on top of our child floats for
   1.549 +  // event handling).
   1.550 +  BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
   1.551 +}
   1.552 +
   1.553 +int
   1.554 +nsTableCellFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const
   1.555 +{
   1.556 +  int skip = 0;
   1.557 +  if (nullptr != GetPrevInFlow()) {
   1.558 +    skip |= LOGICAL_SIDE_B_START;
   1.559 +  }
   1.560 +  if (nullptr != GetNextInFlow()) {
   1.561 +    skip |= LOGICAL_SIDE_B_END;
   1.562 +  }
   1.563 +  return skip;
   1.564 +}
   1.565 +
   1.566 +/* virtual */ nsMargin
   1.567 +nsTableCellFrame::GetBorderOverflow()
   1.568 +{
   1.569 +  return nsMargin(0, 0, 0, 0);
   1.570 +}
   1.571 +
   1.572 +// Align the cell's child frame within the cell
   1.573 +
   1.574 +void nsTableCellFrame::VerticallyAlignChild(nscoord aMaxAscent)
   1.575 +{
   1.576 +  /* It's the 'border-collapse' on the table that matters */
   1.577 +  nsMargin borderPadding = GetUsedBorderAndPadding();
   1.578 +
   1.579 +  nscoord topInset = borderPadding.top;
   1.580 +  nscoord bottomInset = borderPadding.bottom;
   1.581 +
   1.582 +  uint8_t verticalAlignFlags = GetVerticalAlign();
   1.583 +
   1.584 +  nscoord height = mRect.height;
   1.585 +  nsIFrame* firstKid = mFrames.FirstChild();
   1.586 +  NS_ASSERTION(firstKid, "Frame construction error, a table cell always has an inner cell frame");
   1.587 +  nsRect kidRect = firstKid->GetRect();
   1.588 +  nscoord childHeight = kidRect.height;
   1.589 +
   1.590 +  // Vertically align the child
   1.591 +  nscoord kidYTop = 0;
   1.592 +  switch (verticalAlignFlags)
   1.593 +  {
   1.594 +    case NS_STYLE_VERTICAL_ALIGN_BASELINE:
   1.595 +      // Align the baselines of the child frame with the baselines of
   1.596 +      // other children in the same row which have 'vertical-align: baseline'
   1.597 +      kidYTop = topInset + aMaxAscent - GetCellBaseline();
   1.598 +    break;
   1.599 +
   1.600 +    case NS_STYLE_VERTICAL_ALIGN_TOP:
   1.601 +      // Align the top of the child frame with the top of the content area,
   1.602 +      kidYTop = topInset;
   1.603 +    break;
   1.604 +
   1.605 +    case NS_STYLE_VERTICAL_ALIGN_BOTTOM:
   1.606 +      // Align the bottom of the child frame with the bottom of the content area,
   1.607 +      kidYTop = height - childHeight - bottomInset;
   1.608 +    break;
   1.609 +
   1.610 +    default:
   1.611 +    case NS_STYLE_VERTICAL_ALIGN_MIDDLE:
   1.612 +      // Align the middle of the child frame with the middle of the content area,
   1.613 +      kidYTop = (height - childHeight - bottomInset + topInset) / 2;
   1.614 +  }
   1.615 +  // if the content is larger than the cell height align from top
   1.616 +  kidYTop = std::max(0, kidYTop);
   1.617 +
   1.618 +  if (kidYTop != kidRect.y) {
   1.619 +    // Invalidate at the old position first
   1.620 +    firstKid->InvalidateFrameSubtree();
   1.621 +  }
   1.622 +
   1.623 +  firstKid->SetPosition(nsPoint(kidRect.x, kidYTop));
   1.624 +  nsHTMLReflowMetrics desiredSize(GetWritingMode()); // ???
   1.625 +  desiredSize.Width() = mRect.width;
   1.626 +  desiredSize.Height() = mRect.height;
   1.627 +
   1.628 +  nsRect overflow(nsPoint(0,0), GetSize());
   1.629 +  overflow.Inflate(GetBorderOverflow());
   1.630 +  desiredSize.mOverflowAreas.SetAllTo(overflow);
   1.631 +  ConsiderChildOverflow(desiredSize.mOverflowAreas, firstKid);
   1.632 +  FinishAndStoreOverflow(&desiredSize);
   1.633 +  if (kidYTop != kidRect.y) {
   1.634 +    // Make sure any child views are correctly positioned. We know the inner table
   1.635 +    // cell won't have a view
   1.636 +    nsContainerFrame::PositionChildViews(firstKid);
   1.637 +
   1.638 +    // Invalidate new overflow rect
   1.639 +    firstKid->InvalidateFrameSubtree();
   1.640 +  }
   1.641 +  if (HasView()) {
   1.642 +    nsContainerFrame::SyncFrameViewAfterReflow(PresContext(), this,
   1.643 +                                               GetView(),
   1.644 +                                               desiredSize.VisualOverflow(), 0);
   1.645 +  }
   1.646 +}
   1.647 +
   1.648 +bool
   1.649 +nsTableCellFrame::UpdateOverflow()
   1.650 +{
   1.651 +  nsRect bounds(nsPoint(0,0), GetSize());
   1.652 +  bounds.Inflate(GetBorderOverflow());
   1.653 +  nsOverflowAreas overflowAreas(bounds, bounds);
   1.654 +
   1.655 +  nsLayoutUtils::UnionChildOverflow(this, overflowAreas);
   1.656 +
   1.657 +  return FinishAndStoreOverflow(overflowAreas, GetSize());
   1.658 +}
   1.659 +
   1.660 +// Per CSS 2.1, we map 'sub', 'super', 'text-top', 'text-bottom',
   1.661 +// length, percentage, and calc() values to 'baseline'.
   1.662 +uint8_t
   1.663 +nsTableCellFrame::GetVerticalAlign() const
   1.664 +{
   1.665 +  const nsStyleCoord& verticalAlign = StyleTextReset()->mVerticalAlign;
   1.666 +  if (verticalAlign.GetUnit() == eStyleUnit_Enumerated) {
   1.667 +    uint8_t value = verticalAlign.GetIntValue();
   1.668 +    if (value == NS_STYLE_VERTICAL_ALIGN_TOP ||
   1.669 +        value == NS_STYLE_VERTICAL_ALIGN_MIDDLE ||
   1.670 +        value == NS_STYLE_VERTICAL_ALIGN_BOTTOM) {
   1.671 +      return value;
   1.672 +    }
   1.673 +  }
   1.674 +  return NS_STYLE_VERTICAL_ALIGN_BASELINE;
   1.675 +}
   1.676 +
   1.677 +bool
   1.678 +nsTableCellFrame::CellHasVisibleContent(nscoord       height,
   1.679 +                                        nsTableFrame* tableFrame,
   1.680 +                                        nsIFrame*     kidFrame)
   1.681 +{
   1.682 +  // see  http://www.w3.org/TR/CSS21/tables.html#empty-cells
   1.683 +  if (height > 0)
   1.684 +    return true;
   1.685 +  if (tableFrame->IsBorderCollapse())
   1.686 +    return true;
   1.687 +  nsIFrame* innerFrame = kidFrame->GetFirstPrincipalChild();
   1.688 +  while(innerFrame) {
   1.689 +    nsIAtom* frameType = innerFrame->GetType();
   1.690 +    if (nsGkAtoms::textFrame == frameType) {
   1.691 +       nsTextFrame* textFrame = static_cast<nsTextFrame*>(innerFrame);
   1.692 +       if (textFrame->HasNoncollapsedCharacters())
   1.693 +         return true;
   1.694 +    }
   1.695 +    else if (nsGkAtoms::placeholderFrame != frameType) {
   1.696 +      return true;
   1.697 +    }
   1.698 +    else {
   1.699 +      nsIFrame *floatFrame = nsLayoutUtils::GetFloatFromPlaceholder(innerFrame);
   1.700 +      if (floatFrame)
   1.701 +        return true;
   1.702 +    }
   1.703 +    innerFrame = innerFrame->GetNextSibling();
   1.704 +  }	
   1.705 +  return false;
   1.706 +}
   1.707 +
   1.708 +nscoord
   1.709 +nsTableCellFrame::GetCellBaseline() const
   1.710 +{
   1.711 +  // Ignore the position of the inner frame relative to the cell frame
   1.712 +  // since we want the position as though the inner were top-aligned.
   1.713 +  nsIFrame *inner = mFrames.FirstChild();
   1.714 +  nscoord borderPadding = GetUsedBorderAndPadding().top;
   1.715 +  nscoord result;
   1.716 +  if (nsLayoutUtils::GetFirstLineBaseline(inner, &result))
   1.717 +    return result + borderPadding;
   1.718 +  return inner->GetContentRect().YMost() - inner->GetPosition().y +
   1.719 +         borderPadding;
   1.720 +}
   1.721 +
   1.722 +int32_t nsTableCellFrame::GetRowSpan()
   1.723 +{
   1.724 +  int32_t rowSpan=1;
   1.725 +  nsGenericHTMLElement *hc = nsGenericHTMLElement::FromContent(mContent);
   1.726 +
   1.727 +  // Don't look at the content's rowspan if we're a pseudo cell
   1.728 +  if (hc && !StyleContext()->GetPseudo()) {
   1.729 +    const nsAttrValue* attr = hc->GetParsedAttr(nsGkAtoms::rowspan);
   1.730 +    // Note that we don't need to check the tag name, because only table cells
   1.731 +    // and table headers parse the "rowspan" attribute into an integer.
   1.732 +    if (attr && attr->Type() == nsAttrValue::eInteger) {
   1.733 +       rowSpan = attr->GetIntegerValue();
   1.734 +    }
   1.735 +  }
   1.736 +  return rowSpan;
   1.737 +}
   1.738 +
   1.739 +int32_t nsTableCellFrame::GetColSpan()
   1.740 +{
   1.741 +  int32_t colSpan=1;
   1.742 +  nsGenericHTMLElement *hc = nsGenericHTMLElement::FromContent(mContent);
   1.743 +
   1.744 +  // Don't look at the content's colspan if we're a pseudo cell
   1.745 +  if (hc && !StyleContext()->GetPseudo()) {
   1.746 +    const nsAttrValue* attr = hc->GetParsedAttr(nsGkAtoms::colspan);
   1.747 +    // Note that we don't need to check the tag name, because only table cells
   1.748 +    // and table headers parse the "colspan" attribute into an integer.
   1.749 +    if (attr && attr->Type() == nsAttrValue::eInteger) {
   1.750 +       colSpan = attr->GetIntegerValue();
   1.751 +    }
   1.752 +  }
   1.753 +  return colSpan;
   1.754 +}
   1.755 +
   1.756 +/* virtual */ nscoord
   1.757 +nsTableCellFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
   1.758 +{
   1.759 +  nscoord result = 0;
   1.760 +  DISPLAY_MIN_WIDTH(this, result);
   1.761 +
   1.762 +  nsIFrame *inner = mFrames.FirstChild();
   1.763 +  result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext, inner,
   1.764 +                                                    nsLayoutUtils::MIN_WIDTH);
   1.765 +  return result;
   1.766 +}
   1.767 +
   1.768 +/* virtual */ nscoord
   1.769 +nsTableCellFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
   1.770 +{
   1.771 +  nscoord result = 0;
   1.772 +  DISPLAY_PREF_WIDTH(this, result);
   1.773 +
   1.774 +  nsIFrame *inner = mFrames.FirstChild();
   1.775 +  result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext, inner,
   1.776 +                                                nsLayoutUtils::PREF_WIDTH);
   1.777 +  return result;
   1.778 +}
   1.779 +
   1.780 +/* virtual */ nsIFrame::IntrinsicWidthOffsetData
   1.781 +nsTableCellFrame::IntrinsicWidthOffsets(nsRenderingContext* aRenderingContext)
   1.782 +{
   1.783 +  IntrinsicWidthOffsetData result =
   1.784 +    nsContainerFrame::IntrinsicWidthOffsets(aRenderingContext);
   1.785 +
   1.786 +  result.hMargin = 0;
   1.787 +  result.hPctMargin = 0;
   1.788 +
   1.789 +  nsMargin border;
   1.790 +  GetBorderWidth(border);
   1.791 +  result.hBorder = border.LeftRight();
   1.792 +
   1.793 +  return result;
   1.794 +}
   1.795 +
   1.796 +#ifdef DEBUG
   1.797 +#define PROBABLY_TOO_LARGE 1000000
   1.798 +static
   1.799 +void DebugCheckChildSize(nsIFrame*            aChild,
   1.800 +                         nsHTMLReflowMetrics& aMet,
   1.801 +                         nsSize&              aAvailSize)
   1.802 +{
   1.803 +  if ((aMet.Width() < 0) || (aMet.Width() > PROBABLY_TOO_LARGE)) {
   1.804 +    printf("WARNING: cell content %p has large width %d \n",
   1.805 +           static_cast<void*>(aChild), int32_t(aMet.Width()));
   1.806 +  }
   1.807 +}
   1.808 +#endif
   1.809 +
   1.810 +// the computed height for the cell, which descendants use for percent height calculations
   1.811 +// it is the height (minus border, padding) of the cell's first in flow during its final
   1.812 +// reflow without an unconstrained height.
   1.813 +static nscoord
   1.814 +CalcUnpaginagedHeight(nsPresContext*        aPresContext,
   1.815 +                      nsTableCellFrame&     aCellFrame,
   1.816 +                      nsTableFrame&         aTableFrame,
   1.817 +                      nscoord               aVerticalBorderPadding)
   1.818 +{
   1.819 +  const nsTableCellFrame* firstCellInFlow =
   1.820 +    static_cast<nsTableCellFrame*>(aCellFrame.FirstInFlow());
   1.821 +  nsTableFrame* firstTableInFlow  =
   1.822 +    static_cast<nsTableFrame*>(aTableFrame.FirstInFlow());
   1.823 +  nsTableRowFrame* row =
   1.824 +    static_cast<nsTableRowFrame*>(firstCellInFlow->GetParent());
   1.825 +  nsTableRowGroupFrame* firstRGInFlow =
   1.826 +    static_cast<nsTableRowGroupFrame*>(row->GetParent());
   1.827 +
   1.828 +  int32_t rowIndex;
   1.829 +  firstCellInFlow->GetRowIndex(rowIndex);
   1.830 +  int32_t rowSpan = aTableFrame.GetEffectiveRowSpan(*firstCellInFlow);
   1.831 +  nscoord cellSpacing = firstTableInFlow->GetCellSpacingX();
   1.832 +
   1.833 +  nscoord computedHeight = ((rowSpan - 1) * cellSpacing) - aVerticalBorderPadding;
   1.834 +  int32_t rowX;
   1.835 +  for (row = firstRGInFlow->GetFirstRow(), rowX = 0; row; row = row->GetNextRow(), rowX++) {
   1.836 +    if (rowX > rowIndex + rowSpan - 1) {
   1.837 +      break;
   1.838 +    }
   1.839 +    else if (rowX >= rowIndex) {
   1.840 +      computedHeight += row->GetUnpaginatedHeight(aPresContext);
   1.841 +    }
   1.842 +  }
   1.843 +  return computedHeight;
   1.844 +}
   1.845 +
   1.846 +nsresult nsTableCellFrame::Reflow(nsPresContext*           aPresContext,
   1.847 +                                   nsHTMLReflowMetrics&     aDesiredSize,
   1.848 +                                   const nsHTMLReflowState& aReflowState,
   1.849 +                                   nsReflowStatus&          aStatus)
   1.850 +{
   1.851 +  DO_GLOBAL_REFLOW_COUNT("nsTableCellFrame");
   1.852 +  DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
   1.853 +
   1.854 +  if (aReflowState.mFlags.mSpecialHeightReflow) {
   1.855 +    FirstInFlow()->AddStateBits(NS_TABLE_CELL_HAD_SPECIAL_REFLOW);
   1.856 +  }
   1.857 +
   1.858 +  // see if a special height reflow needs to occur due to having a pct height
   1.859 +  nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState);
   1.860 +
   1.861 +  aStatus = NS_FRAME_COMPLETE;
   1.862 +  nsSize availSize(aReflowState.AvailableWidth(), aReflowState.AvailableHeight());
   1.863 +
   1.864 +  nsMargin borderPadding = aReflowState.ComputedPhysicalPadding();
   1.865 +  nsMargin border;
   1.866 +  GetBorderWidth(border);
   1.867 +  borderPadding += border;
   1.868 +
   1.869 +  nscoord topInset    = borderPadding.top;
   1.870 +  nscoord rightInset  = borderPadding.right;
   1.871 +  nscoord bottomInset = borderPadding.bottom;
   1.872 +  nscoord leftInset   = borderPadding.left;
   1.873 +
   1.874 +  // reduce available space by insets, if we're in a constrained situation
   1.875 +  availSize.width -= leftInset + rightInset;
   1.876 +  if (NS_UNCONSTRAINEDSIZE != availSize.height)
   1.877 +    availSize.height -= topInset + bottomInset;
   1.878 +
   1.879 +  // Try to reflow the child into the available space. It might not
   1.880 +  // fit or might need continuing.
   1.881 +  if (availSize.height < 0)
   1.882 +    availSize.height = 1;
   1.883 +
   1.884 +  nsHTMLReflowMetrics kidSize(aReflowState.GetWritingMode(), aDesiredSize.mFlags);
   1.885 +  kidSize.Width() = kidSize.Height() = 0;
   1.886 +  SetPriorAvailWidth(aReflowState.AvailableWidth());
   1.887 +  nsIFrame* firstKid = mFrames.FirstChild();
   1.888 +  NS_ASSERTION(firstKid, "Frame construction error, a table cell always has an inner cell frame");
   1.889 +  nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
   1.890 +
   1.891 +  if (aReflowState.mFlags.mSpecialHeightReflow) {
   1.892 +    const_cast<nsHTMLReflowState&>(aReflowState).SetComputedHeight(mRect.height - topInset - bottomInset);
   1.893 +    DISPLAY_REFLOW_CHANGE();
   1.894 +  }
   1.895 +  else if (aPresContext->IsPaginated()) {
   1.896 +    nscoord computedUnpaginatedHeight =
   1.897 +      CalcUnpaginagedHeight(aPresContext, (nsTableCellFrame&)*this,
   1.898 +                            *tableFrame, topInset + bottomInset);
   1.899 +    if (computedUnpaginatedHeight > 0) {
   1.900 +      const_cast<nsHTMLReflowState&>(aReflowState).SetComputedHeight(computedUnpaginatedHeight);
   1.901 +      DISPLAY_REFLOW_CHANGE();
   1.902 +    }
   1.903 +  }
   1.904 +  else {
   1.905 +    SetHasPctOverHeight(false);
   1.906 +  }
   1.907 +
   1.908 +  nsHTMLReflowState kidReflowState(aPresContext, aReflowState, firstKid,
   1.909 +                                   availSize);
   1.910 +
   1.911 +  // Don't be a percent height observer if we're in the middle of
   1.912 +  // special-height reflow, in case we get an accidental NotifyPercentHeight()
   1.913 +  // call (which we shouldn't honor during special-height reflow)
   1.914 +  if (!aReflowState.mFlags.mSpecialHeightReflow) {
   1.915 +    // mPercentHeightObserver is for children of cells in quirks mode,
   1.916 +    // but only those than are tables in standards mode.  NeedsToObserve
   1.917 +    // will determine how far this is propagated to descendants.
   1.918 +    kidReflowState.mPercentHeightObserver = this;
   1.919 +  }
   1.920 +  // Don't propagate special height reflow state to our kids
   1.921 +  kidReflowState.mFlags.mSpecialHeightReflow = false;
   1.922 +
   1.923 +  if (aReflowState.mFlags.mSpecialHeightReflow ||
   1.924 +      (FirstInFlow()->GetStateBits() & NS_TABLE_CELL_HAD_SPECIAL_REFLOW)) {
   1.925 +    // We need to force the kid to have mVResize set if we've had a
   1.926 +    // special reflow in the past, since the non-special reflow needs to
   1.927 +    // resize back to what it was without the special height reflow.
   1.928 +    kidReflowState.mFlags.mVResize = true;
   1.929 +  }
   1.930 +
   1.931 +  nsPoint kidOrigin(leftInset, topInset);
   1.932 +  nsRect origRect = firstKid->GetRect();
   1.933 +  nsRect origVisualOverflow = firstKid->GetVisualOverflowRect();
   1.934 +  bool firstReflow = (firstKid->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
   1.935 +
   1.936 +  ReflowChild(firstKid, aPresContext, kidSize, kidReflowState,
   1.937 +              kidOrigin.x, kidOrigin.y, 0, aStatus);
   1.938 +  if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) {
   1.939 +    // Don't pass OVERFLOW_INCOMPLETE through tables until they can actually handle it
   1.940 +    //XXX should paginate overflow as overflow, but not in this patch (bug 379349)
   1.941 +    NS_FRAME_SET_INCOMPLETE(aStatus);
   1.942 +    printf("Set table cell incomplete %p\n", static_cast<void*>(this));
   1.943 +  }
   1.944 +
   1.945 +  // XXXbz is this invalidate actually needed, really?
   1.946 +  if (GetStateBits() & NS_FRAME_IS_DIRTY) {
   1.947 +    InvalidateFrameSubtree();
   1.948 +  }
   1.949 +
   1.950 +#ifdef DEBUG
   1.951 +  DebugCheckChildSize(firstKid, kidSize, availSize);
   1.952 +#endif
   1.953 +
   1.954 +  // 0 dimensioned cells need to be treated specially in Standard/NavQuirks mode
   1.955 +  // see testcase "emptyCells.html"
   1.956 +  nsIFrame* prevInFlow = GetPrevInFlow();
   1.957 +  bool isEmpty;
   1.958 +  if (prevInFlow) {
   1.959 +    isEmpty = static_cast<nsTableCellFrame*>(prevInFlow)->GetContentEmpty();
   1.960 +  } else {
   1.961 +    isEmpty = !CellHasVisibleContent(kidSize.Height(), tableFrame, firstKid);
   1.962 +  }
   1.963 +  SetContentEmpty(isEmpty);
   1.964 +
   1.965 +  // Place the child
   1.966 +  FinishReflowChild(firstKid, aPresContext, kidSize, &kidReflowState,
   1.967 +                    kidOrigin.x, kidOrigin.y, 0);
   1.968 +
   1.969 +  nsTableFrame::InvalidateTableFrame(firstKid, origRect, origVisualOverflow,
   1.970 +                                     firstReflow);
   1.971 +
   1.972 +  // first, compute the height which can be set w/o being restricted by aMaxSize.height
   1.973 +  nscoord cellHeight = kidSize.Height();
   1.974 +
   1.975 +  if (NS_UNCONSTRAINEDSIZE != cellHeight) {
   1.976 +    cellHeight += topInset + bottomInset;
   1.977 +  }
   1.978 +
   1.979 +  // next determine the cell's width
   1.980 +  nscoord cellWidth = kidSize.Width();      // at this point, we've factored in the cell's style attributes
   1.981 +
   1.982 +  // factor in border and padding
   1.983 +  if (NS_UNCONSTRAINEDSIZE != cellWidth) {
   1.984 +    cellWidth += leftInset + rightInset;
   1.985 +  }
   1.986 +
   1.987 +  // set the cell's desired size and max element size
   1.988 +  aDesiredSize.Width() = cellWidth;
   1.989 +  aDesiredSize.Height() = cellHeight;
   1.990 +
   1.991 +  // the overflow area will be computed when the child will be vertically aligned
   1.992 +
   1.993 +  if (aReflowState.mFlags.mSpecialHeightReflow) {
   1.994 +    if (aDesiredSize.Height() > mRect.height) {
   1.995 +      // set a bit indicating that the pct height contents exceeded
   1.996 +      // the height that they could honor in the pass 2 reflow
   1.997 +      SetHasPctOverHeight(true);
   1.998 +    }
   1.999 +    if (NS_UNCONSTRAINEDSIZE == aReflowState.AvailableHeight()) {
  1.1000 +      aDesiredSize.Height() = mRect.height;
  1.1001 +    }
  1.1002 +  }
  1.1003 +
  1.1004 +  // If our parent is in initial reflow, it'll handle invalidating our
  1.1005 +  // entire overflow rect.
  1.1006 +  if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW) &&
  1.1007 +      nsSize(aDesiredSize.Width(), aDesiredSize.Height()) != mRect.Size()) {
  1.1008 +    InvalidateFrame();
  1.1009 +  }
  1.1010 +
  1.1011 +  // remember the desired size for this reflow
  1.1012 +  SetDesiredSize(aDesiredSize);
  1.1013 +
  1.1014 +  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
  1.1015 +  return NS_OK;
  1.1016 +}
  1.1017 +
  1.1018 +/* ----- global methods ----- */
  1.1019 +
  1.1020 +NS_QUERYFRAME_HEAD(nsTableCellFrame)
  1.1021 +  NS_QUERYFRAME_ENTRY(nsTableCellFrame)
  1.1022 +  NS_QUERYFRAME_ENTRY(nsITableCellLayout)
  1.1023 +  NS_QUERYFRAME_ENTRY(nsIPercentHeightObserver)
  1.1024 +NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
  1.1025 +
  1.1026 +#ifdef ACCESSIBILITY
  1.1027 +a11y::AccType
  1.1028 +nsTableCellFrame::AccessibleType()
  1.1029 +{
  1.1030 +  return a11y::eHTMLTableCellType;
  1.1031 +}
  1.1032 +#endif
  1.1033 +
  1.1034 +/* This is primarily for editor access via nsITableLayout */
  1.1035 +NS_IMETHODIMP
  1.1036 +nsTableCellFrame::GetCellIndexes(int32_t &aRowIndex, int32_t &aColIndex)
  1.1037 +{
  1.1038 +  nsresult res = GetRowIndex(aRowIndex);
  1.1039 +  if (NS_FAILED(res))
  1.1040 +  {
  1.1041 +    aColIndex = 0;
  1.1042 +    return res;
  1.1043 +  }
  1.1044 +  aColIndex = mColIndex;
  1.1045 +  return  NS_OK;
  1.1046 +}
  1.1047 +
  1.1048 +nsIFrame*
  1.1049 +NS_NewTableCellFrame(nsIPresShell*   aPresShell,
  1.1050 +                     nsStyleContext* aContext,
  1.1051 +                     bool            aIsBorderCollapse)
  1.1052 +{
  1.1053 +  if (aIsBorderCollapse)
  1.1054 +    return new (aPresShell) nsBCTableCellFrame(aContext);
  1.1055 +  else
  1.1056 +    return new (aPresShell) nsTableCellFrame(aContext);
  1.1057 +}
  1.1058 +
  1.1059 +NS_IMPL_FRAMEARENA_HELPERS(nsBCTableCellFrame)
  1.1060 +
  1.1061 +nsMargin*
  1.1062 +nsTableCellFrame::GetBorderWidth(nsMargin&  aBorder) const
  1.1063 +{
  1.1064 +  aBorder = StyleBorder()->GetComputedBorder();
  1.1065 +  return &aBorder;
  1.1066 +}
  1.1067 +
  1.1068 +nsIAtom*
  1.1069 +nsTableCellFrame::GetType() const
  1.1070 +{
  1.1071 +  return nsGkAtoms::tableCellFrame;
  1.1072 +}
  1.1073 +
  1.1074 +#ifdef DEBUG_FRAME_DUMP
  1.1075 +nsresult
  1.1076 +nsTableCellFrame::GetFrameName(nsAString& aResult) const
  1.1077 +{
  1.1078 +  return MakeFrameName(NS_LITERAL_STRING("TableCell"), aResult);
  1.1079 +}
  1.1080 +#endif
  1.1081 +
  1.1082 +// nsBCTableCellFrame
  1.1083 +
  1.1084 +nsBCTableCellFrame::nsBCTableCellFrame(nsStyleContext* aContext)
  1.1085 +:nsTableCellFrame(aContext)
  1.1086 +{
  1.1087 +  mTopBorder = mRightBorder = mBottomBorder = mLeftBorder = 0;
  1.1088 +}
  1.1089 +
  1.1090 +nsBCTableCellFrame::~nsBCTableCellFrame()
  1.1091 +{
  1.1092 +}
  1.1093 +
  1.1094 +nsIAtom*
  1.1095 +nsBCTableCellFrame::GetType() const
  1.1096 +{
  1.1097 +  return nsGkAtoms::bcTableCellFrame;
  1.1098 +}
  1.1099 +
  1.1100 +/* virtual */ nsMargin
  1.1101 +nsBCTableCellFrame::GetUsedBorder() const
  1.1102 +{
  1.1103 +  nsMargin result;
  1.1104 +  GetBorderWidth(result);
  1.1105 +  return result;
  1.1106 +}
  1.1107 +
  1.1108 +/* virtual */ bool
  1.1109 +nsBCTableCellFrame::GetBorderRadii(nscoord aRadii[8]) const
  1.1110 +{
  1.1111 +  NS_FOR_CSS_HALF_CORNERS(corner) {
  1.1112 +    aRadii[corner] = 0;
  1.1113 +  }
  1.1114 +  return false;
  1.1115 +}
  1.1116 +
  1.1117 +#ifdef DEBUG_FRAME_DUMP
  1.1118 +nsresult
  1.1119 +nsBCTableCellFrame::GetFrameName(nsAString& aResult) const
  1.1120 +{
  1.1121 +  return MakeFrameName(NS_LITERAL_STRING("BCTableCell"), aResult);
  1.1122 +}
  1.1123 +#endif
  1.1124 +
  1.1125 +nsMargin*
  1.1126 +nsBCTableCellFrame::GetBorderWidth(nsMargin&  aBorder) const
  1.1127 +{
  1.1128 +  int32_t aPixelsToTwips = nsPresContext::AppUnitsPerCSSPixel();
  1.1129 +  aBorder.top    = BC_BORDER_BOTTOM_HALF_COORD(aPixelsToTwips, mTopBorder);
  1.1130 +  aBorder.right  = BC_BORDER_LEFT_HALF_COORD(aPixelsToTwips, mRightBorder);
  1.1131 +  aBorder.bottom = BC_BORDER_TOP_HALF_COORD(aPixelsToTwips, mBottomBorder);
  1.1132 +  aBorder.left   = BC_BORDER_RIGHT_HALF_COORD(aPixelsToTwips, mLeftBorder);
  1.1133 +  return &aBorder;
  1.1134 +}
  1.1135 +
  1.1136 +BCPixelSize
  1.1137 +nsBCTableCellFrame::GetBorderWidth(mozilla::css::Side aSide) const
  1.1138 +{
  1.1139 +  switch(aSide) {
  1.1140 +  case NS_SIDE_TOP:
  1.1141 +    return BC_BORDER_BOTTOM_HALF(mTopBorder);
  1.1142 +  case NS_SIDE_RIGHT:
  1.1143 +    return BC_BORDER_LEFT_HALF(mRightBorder);
  1.1144 +  case NS_SIDE_BOTTOM:
  1.1145 +    return BC_BORDER_TOP_HALF(mBottomBorder);
  1.1146 +  default:
  1.1147 +    return BC_BORDER_RIGHT_HALF(mLeftBorder);
  1.1148 +  }
  1.1149 +}
  1.1150 +
  1.1151 +void
  1.1152 +nsBCTableCellFrame::SetBorderWidth(mozilla::css::Side aSide,
  1.1153 +                                   BCPixelSize aValue)
  1.1154 +{
  1.1155 +  switch(aSide) {
  1.1156 +  case NS_SIDE_TOP:
  1.1157 +    mTopBorder = aValue;
  1.1158 +    break;
  1.1159 +  case NS_SIDE_RIGHT:
  1.1160 +    mRightBorder = aValue;
  1.1161 +    break;
  1.1162 +  case NS_SIDE_BOTTOM:
  1.1163 +    mBottomBorder = aValue;
  1.1164 +    break;
  1.1165 +  default:
  1.1166 +    mLeftBorder = aValue;
  1.1167 +  }
  1.1168 +}
  1.1169 +
  1.1170 +/* virtual */ nsMargin
  1.1171 +nsBCTableCellFrame::GetBorderOverflow()
  1.1172 +{
  1.1173 +  nsMargin halfBorder;
  1.1174 +  int32_t p2t = nsPresContext::AppUnitsPerCSSPixel();
  1.1175 +  halfBorder.top = BC_BORDER_TOP_HALF_COORD(p2t, mTopBorder);
  1.1176 +  halfBorder.right = BC_BORDER_RIGHT_HALF_COORD(p2t, mRightBorder);
  1.1177 +  halfBorder.bottom = BC_BORDER_BOTTOM_HALF_COORD(p2t, mBottomBorder);
  1.1178 +  halfBorder.left = BC_BORDER_LEFT_HALF_COORD(p2t, mLeftBorder);
  1.1179 +  return halfBorder;
  1.1180 +}
  1.1181 +
  1.1182 +
  1.1183 +void
  1.1184 +nsBCTableCellFrame::PaintBackground(nsRenderingContext& aRenderingContext,
  1.1185 +                                    const nsRect&        aDirtyRect,
  1.1186 +                                    nsPoint              aPt,
  1.1187 +                                    uint32_t             aFlags)
  1.1188 +{
  1.1189 +  // make border-width reflect the half of the border-collapse
  1.1190 +  // assigned border that's inside the cell
  1.1191 +  nsMargin borderWidth;
  1.1192 +  GetBorderWidth(borderWidth);
  1.1193 +
  1.1194 +  nsStyleBorder myBorder(*StyleBorder());
  1.1195 +
  1.1196 +  NS_FOR_CSS_SIDES(side) {
  1.1197 +    myBorder.SetBorderWidth(side, borderWidth.Side(side));
  1.1198 +  }
  1.1199 +
  1.1200 +  nsRect rect(aPt, GetSize());
  1.1201 +  // bypassing nsCSSRendering::PaintBackground is safe because this kind
  1.1202 +  // of frame cannot be used for the root element
  1.1203 +  nsCSSRendering::PaintBackgroundWithSC(PresContext(), aRenderingContext, this,
  1.1204 +                                        aDirtyRect, rect,
  1.1205 +                                        StyleContext(), myBorder,
  1.1206 +                                        aFlags, nullptr);
  1.1207 +}

mercurial