layout/tables/nsTablePainter.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/tables/nsTablePainter.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,647 @@
     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 +
     1.9 +#include "nsTableFrame.h"
    1.10 +#include "nsTableRowGroupFrame.h"
    1.11 +#include "nsTableRowFrame.h"
    1.12 +#include "nsTableColGroupFrame.h"
    1.13 +#include "nsTableColFrame.h"
    1.14 +#include "nsTableCellFrame.h"
    1.15 +#include "nsTablePainter.h"
    1.16 +#include "nsCSSRendering.h"
    1.17 +#include "nsDisplayList.h"
    1.18 +
    1.19 +/* ~*~ Table Background Painting ~*~
    1.20 +
    1.21 +   Mozilla's Table Background painting follows CSS2.1:17.5.1
    1.22 +   That section does not, however, describe the effect of
    1.23 +   borders on background image positioning. What we do is:
    1.24 +
    1.25 +     - in separate borders, the borders are passed in so that
    1.26 +       their width figures in image positioning, even for rows/cols, which
    1.27 +       don't have visible borders. This is done to allow authors
    1.28 +       to position row backgrounds by, for example, aligning the
    1.29 +       top left corner with the top left padding corner of the
    1.30 +       top left table cell in the row in cases where all cells
    1.31 +       have consistent border widths. If we didn't honor these
    1.32 +       invisible borders, there would be no way to align
    1.33 +       backgrounds with the padding edges, and designs would be
    1.34 +       lost underneath the border.
    1.35 +
    1.36 +     - in collapsing borders, because the borders collapse, we
    1.37 +       use the -continuous border- width to synthesize a border
    1.38 +       style and pass that in instead of using the element's
    1.39 +       assigned style directly.
    1.40 +
    1.41 +       The continuous border on a given edge of an element is
    1.42 +       the collapse of all borders guaranteed to be continuous
    1.43 +       along that edge. Cell borders are ignored (because, for
    1.44 +       example, setting a thick border on the leftmost cell
    1.45 +       should not shift the row background over; this way a
    1.46 +       striped background set on <tr> will line up across rows
    1.47 +       even if the cells are assigned arbitrary border widths.
    1.48 +
    1.49 +       For example, the continuous border on the top edge of a
    1.50 +       row group is the collapse of any row group, row, and
    1.51 +       table borders involved. (The first row group's top would
    1.52 +       be [table-top + row group top + first row top]. It's bottom
    1.53 +       would be [row group bottom + last row bottom + next row
    1.54 +       top + next row group top].)
    1.55 +       The top edge of a column group likewise includes the
    1.56 +       table top, row group top, and first row top borders. However,
    1.57 +       it *also* includes its own top border, since that is guaranteed
    1.58 +       to be continuous. It does not include column borders because
    1.59 +       those are not guaranteed to be continuous: there may be two
    1.60 +       columns with different borders in a single column group.
    1.61 +
    1.62 +       An alternative would be to define the continuous border as
    1.63 +         [table? + row group + row] for horizontal
    1.64 +         [table? + col group + col] for vertical
    1.65 +       This makes it easier to line up backgrounds across elements
    1.66 +       despite varying border widths, but it does not give much
    1.67 +       flexibility in aligning /to/ those border widths.
    1.68 +*/
    1.69 +
    1.70 +
    1.71 +/* ~*~ TableBackgroundPainter ~*~
    1.72 +
    1.73 +   The TableBackgroundPainter is created and destroyed in one painting call.
    1.74 +   Its principal function is PaintTable, which paints all table element
    1.75 +   backgrounds. The initial code in that method sets up an array of column
    1.76 +   data that caches the background styles and the border sizes for the
    1.77 +   columns and colgroups in TableBackgroundData structs in mCols. Data for
    1.78 +   BC borders are calculated and stashed in a synthesized border style struct
    1.79 +   in the data struct since collapsed borders aren't the same width as style-
    1.80 +   assigned borders. The data struct optimizes by only doing this if there's
    1.81 +   an image background; otherwise we don't care. //XXX should also check background-origin
    1.82 +   The class then loops through the row groups, rows, and cells. It uses
    1.83 +   the mRowGroup and mRow TableBackgroundData structs to cache data for
    1.84 +   the current frame in the loop. At the cell level, it paints the backgrounds,
    1.85 +   one over the other, inside the cell rect.
    1.86 +
    1.87 +   The exception to this pattern is when a table element creates a (pseudo)
    1.88 +   stacking context. Elements with stacking contexts (e.g., 'opacity' applied)
    1.89 +   are <dfn>passed through</dfn>, which means their data (and their
    1.90 +   descendants' data) are not cached. The full loop is still executed, however,
    1.91 +   so that underlying layers can get painted at the cell level.
    1.92 +
    1.93 +   The TableBackgroundPainter is then destroyed.
    1.94 +
    1.95 +   Elements with stacking contexts set up their own painter to finish the
    1.96 +   painting process, since they were skipped. They call the appropriate
    1.97 +   sub-part of the loop (e.g. PaintRow) which will paint the frame and
    1.98 +   descendants. Note that it is permissible according to CSS2.1 to ignore'
    1.99 +   'position:relative' (and implicitly, 'opacity') on table parts so that
   1.100 +   table parts can never create stacking contexts; if we want to, we can
   1.101 +   implement that, and then we won't have to deal with TableBackgroundPainter
   1.102 +   being used anywhere but from the nsTableFrame.
   1.103 +   
   1.104 +   XXX views are going 
   1.105 + */
   1.106 +
   1.107 +TableBackgroundPainter::TableBackgroundData::TableBackgroundData()
   1.108 +  : mFrame(nullptr),
   1.109 +    mVisible(false),
   1.110 +    mBorder(nullptr),
   1.111 +    mSynthBorder(nullptr)
   1.112 +{
   1.113 +  MOZ_COUNT_CTOR(TableBackgroundData);
   1.114 +}
   1.115 +
   1.116 +TableBackgroundPainter::TableBackgroundData::~TableBackgroundData()
   1.117 +{
   1.118 +  NS_ASSERTION(!mSynthBorder, "must call Destroy before dtor");
   1.119 +  MOZ_COUNT_DTOR(TableBackgroundData);
   1.120 +}
   1.121 +
   1.122 +void
   1.123 +TableBackgroundPainter::TableBackgroundData::Destroy(nsPresContext* aPresContext)
   1.124 +{
   1.125 +  NS_PRECONDITION(aPresContext, "null prescontext");
   1.126 +  if (mSynthBorder) {
   1.127 +    mSynthBorder->Destroy(aPresContext);
   1.128 +    mSynthBorder = nullptr;
   1.129 +  }
   1.130 +}
   1.131 +
   1.132 +void
   1.133 +TableBackgroundPainter::TableBackgroundData::Clear()
   1.134 +{
   1.135 +  mRect.SetEmpty();
   1.136 +  mFrame = nullptr;
   1.137 +  mBorder = nullptr;
   1.138 +  mVisible = false;
   1.139 +}
   1.140 +
   1.141 +void
   1.142 +TableBackgroundPainter::TableBackgroundData::SetFrame(nsIFrame* aFrame)
   1.143 +{
   1.144 +  NS_PRECONDITION(aFrame, "null frame");
   1.145 +  mFrame = aFrame;
   1.146 +  mRect = aFrame->GetRect();
   1.147 +}
   1.148 +
   1.149 +void
   1.150 +TableBackgroundPainter::TableBackgroundData::SetData()
   1.151 +{
   1.152 +  NS_PRECONDITION(mFrame, "null frame");
   1.153 +  if (mFrame->IsVisibleForPainting()) {
   1.154 +    mVisible = true;
   1.155 +    mBorder = mFrame->StyleBorder();
   1.156 +  }
   1.157 +}
   1.158 +
   1.159 +void
   1.160 +TableBackgroundPainter::TableBackgroundData::SetFull(nsIFrame* aFrame)
   1.161 +{
   1.162 +  NS_PRECONDITION(aFrame, "null frame");
   1.163 +  SetFrame(aFrame);
   1.164 +  SetData();
   1.165 +}
   1.166 +
   1.167 +inline bool
   1.168 +TableBackgroundPainter::TableBackgroundData::ShouldSetBCBorder()
   1.169 +{
   1.170 +  /* we only need accurate border data when positioning background images*/
   1.171 +  if (!mVisible) {
   1.172 +    return false;
   1.173 +  }
   1.174 +
   1.175 +  const nsStyleBackground *bg = mFrame->StyleBackground();
   1.176 +  NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) {
   1.177 +    if (!bg->mLayers[i].mImage.IsEmpty())
   1.178 +      return true;
   1.179 +  }
   1.180 +  return false;
   1.181 +}
   1.182 +
   1.183 +nsresult
   1.184 +TableBackgroundPainter::TableBackgroundData::SetBCBorder(nsMargin& aBorder,
   1.185 +                                                         TableBackgroundPainter* aPainter)
   1.186 +{
   1.187 +  NS_PRECONDITION(aPainter, "null painter");
   1.188 +  if (!mSynthBorder) {
   1.189 +    mSynthBorder = new (aPainter->mPresContext)
   1.190 +                        nsStyleBorder(aPainter->mZeroBorder);
   1.191 +    if (!mSynthBorder) return NS_ERROR_OUT_OF_MEMORY;
   1.192 +  }
   1.193 +
   1.194 +  NS_FOR_CSS_SIDES(side) {
   1.195 +    mSynthBorder->SetBorderWidth(side, aBorder.Side(side));
   1.196 +  }
   1.197 +  
   1.198 +  mBorder = mSynthBorder;
   1.199 +  return NS_OK;
   1.200 +}
   1.201 +
   1.202 +TableBackgroundPainter::TableBackgroundPainter(nsTableFrame*        aTableFrame,
   1.203 +                                               Origin               aOrigin,
   1.204 +                                               nsPresContext*       aPresContext,
   1.205 +                                               nsRenderingContext& aRenderingContext,
   1.206 +                                               const nsRect&        aDirtyRect,
   1.207 +                                               const nsPoint&       aRenderPt,
   1.208 +                                               uint32_t             aBGPaintFlags)
   1.209 +  : mPresContext(aPresContext),
   1.210 +    mRenderingContext(aRenderingContext),
   1.211 +    mRenderPt(aRenderPt),
   1.212 +    mDirtyRect(aDirtyRect),
   1.213 +    mOrigin(aOrigin),
   1.214 +    mCols(nullptr),
   1.215 +    mZeroBorder(aPresContext),
   1.216 +    mBGPaintFlags(aBGPaintFlags)
   1.217 +{
   1.218 +  MOZ_COUNT_CTOR(TableBackgroundPainter);
   1.219 +
   1.220 +  NS_FOR_CSS_SIDES(side) {
   1.221 +    mZeroBorder.SetBorderStyle(side, NS_STYLE_BORDER_STYLE_SOLID);
   1.222 +    mZeroBorder.SetBorderWidth(side, 0);
   1.223 +  }
   1.224 +
   1.225 +  mIsBorderCollapse = aTableFrame->IsBorderCollapse();
   1.226 +#ifdef DEBUG
   1.227 +  mCompatMode = mPresContext->CompatibilityMode();
   1.228 +#endif
   1.229 +  mNumCols = aTableFrame->GetColCount();
   1.230 +}
   1.231 +
   1.232 +TableBackgroundPainter::~TableBackgroundPainter()
   1.233 +{
   1.234 +  if (mCols) {
   1.235 +    TableBackgroundData* lastColGroup = nullptr;
   1.236 +    for (uint32_t i = 0; i < mNumCols; i++) {
   1.237 +      if (mCols[i].mColGroup != lastColGroup) {
   1.238 +        lastColGroup = mCols[i].mColGroup;
   1.239 +        NS_ASSERTION(mCols[i].mColGroup, "colgroup data should not be null - bug 237421");
   1.240 +        // we need to wallpaper a over zero pointer deref, bug 237421 will have the real fix
   1.241 +        if(lastColGroup)
   1.242 +          lastColGroup->Destroy(mPresContext);
   1.243 +        delete lastColGroup;
   1.244 +      }
   1.245 +      mCols[i].mColGroup = nullptr;
   1.246 +      mCols[i].mCol.Destroy(mPresContext);
   1.247 +    }
   1.248 +    delete [] mCols;
   1.249 +  }
   1.250 +  mRowGroup.Destroy(mPresContext);
   1.251 +  mRow.Destroy(mPresContext);
   1.252 +  MOZ_COUNT_DTOR(TableBackgroundPainter);
   1.253 +}
   1.254 +
   1.255 +nsresult
   1.256 +TableBackgroundPainter::PaintTableFrame(nsTableFrame*         aTableFrame,
   1.257 +                                        nsTableRowGroupFrame* aFirstRowGroup,
   1.258 +                                        nsTableRowGroupFrame* aLastRowGroup,
   1.259 +                                        const nsMargin&       aDeflate)
   1.260 +{
   1.261 +  NS_PRECONDITION(aTableFrame, "null frame");
   1.262 +  TableBackgroundData tableData;
   1.263 +  tableData.SetFull(aTableFrame);
   1.264 +  tableData.mRect.MoveTo(0,0); //using table's coords
   1.265 +  tableData.mRect.Deflate(aDeflate);
   1.266 +  if (mIsBorderCollapse && tableData.ShouldSetBCBorder()) {
   1.267 +    if (aFirstRowGroup && aLastRowGroup && mNumCols > 0) {
   1.268 +      //only handle non-degenerate tables; we need a more robust BC model
   1.269 +      //to make degenerate tables' borders reasonable to deal with
   1.270 +      nsMargin border, tempBorder;
   1.271 +      nsTableColFrame* colFrame = aTableFrame->GetColFrame(mNumCols - 1);
   1.272 +      if (colFrame) {
   1.273 +        colFrame->GetContinuousBCBorderWidth(tempBorder);
   1.274 +      }
   1.275 +      border.right = tempBorder.right;
   1.276 +
   1.277 +      aLastRowGroup->GetContinuousBCBorderWidth(tempBorder);
   1.278 +      border.bottom = tempBorder.bottom;
   1.279 +
   1.280 +      nsTableRowFrame* rowFrame = aFirstRowGroup->GetFirstRow();
   1.281 +      if (rowFrame) {
   1.282 +        rowFrame->GetContinuousBCBorderWidth(tempBorder);
   1.283 +        border.top = tempBorder.top;
   1.284 +      }
   1.285 +
   1.286 +      border.left = aTableFrame->GetContinuousLeftBCBorderWidth();
   1.287 +
   1.288 +      nsresult rv = tableData.SetBCBorder(border, this);
   1.289 +      if (NS_FAILED(rv)) {
   1.290 +        tableData.Destroy(mPresContext);
   1.291 +        return rv;
   1.292 +      }
   1.293 +    }
   1.294 +  }
   1.295 +  if (tableData.IsVisible()) {
   1.296 +    nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
   1.297 +                                          tableData.mFrame, mDirtyRect,
   1.298 +                                          tableData.mRect + mRenderPt,
   1.299 +                                          tableData.mFrame->StyleContext(),
   1.300 +                                          *tableData.mBorder,
   1.301 +                                          mBGPaintFlags);
   1.302 +  }
   1.303 +  tableData.Destroy(mPresContext);
   1.304 +  return NS_OK;
   1.305 +}
   1.306 +
   1.307 +void
   1.308 +TableBackgroundPainter::TranslateContext(nscoord aDX,
   1.309 +                                         nscoord aDY)
   1.310 +{
   1.311 +  mRenderPt += nsPoint(aDX, aDY);
   1.312 +  if (mCols) {
   1.313 +    TableBackgroundData* lastColGroup = nullptr;
   1.314 +    for (uint32_t i = 0; i < mNumCols; i++) {
   1.315 +      mCols[i].mCol.mRect.MoveBy(-aDX, -aDY);
   1.316 +      if (lastColGroup != mCols[i].mColGroup) {
   1.317 +        NS_ASSERTION(mCols[i].mColGroup, "colgroup data should not be null - bug 237421");
   1.318 +        // we need to wallpaper a over zero pointer deref, bug 237421 will have the real fix
   1.319 +        if (!mCols[i].mColGroup)
   1.320 +          return;
   1.321 +        mCols[i].mColGroup->mRect.MoveBy(-aDX, -aDY);
   1.322 +        lastColGroup = mCols[i].mColGroup;
   1.323 +      }
   1.324 +    }
   1.325 +  }
   1.326 +}
   1.327 +
   1.328 +nsresult
   1.329 +TableBackgroundPainter::PaintTable(nsTableFrame*   aTableFrame,
   1.330 +                                   const nsMargin& aDeflate,
   1.331 +                                   bool            aPaintTableBackground)
   1.332 +{
   1.333 +  NS_PRECONDITION(aTableFrame, "null table frame");
   1.334 +
   1.335 +  nsTableFrame::RowGroupArray rowGroups;
   1.336 +  aTableFrame->OrderRowGroups(rowGroups);
   1.337 +
   1.338 +  if (rowGroups.Length() < 1) { //degenerate case
   1.339 +    if (aPaintTableBackground) {
   1.340 +      PaintTableFrame(aTableFrame, nullptr, nullptr, nsMargin(0,0,0,0));
   1.341 +    }
   1.342 +    /* No cells; nothing else to paint */
   1.343 +    return NS_OK;
   1.344 +  }
   1.345 +
   1.346 +  if (aPaintTableBackground) {
   1.347 +    PaintTableFrame(aTableFrame, rowGroups[0], rowGroups[rowGroups.Length() - 1],
   1.348 +                    aDeflate);
   1.349 +  }
   1.350 +
   1.351 +  /*Set up column background/border data*/
   1.352 +  if (mNumCols > 0) {
   1.353 +    nsFrameList& colGroupList = aTableFrame->GetColGroups();
   1.354 +    NS_ASSERTION(colGroupList.FirstChild(), "table should have at least one colgroup");
   1.355 +
   1.356 +    mCols = new ColData[mNumCols];
   1.357 +    if (!mCols) return NS_ERROR_OUT_OF_MEMORY;
   1.358 +
   1.359 +    TableBackgroundData* cgData = nullptr;
   1.360 +    nsMargin border;
   1.361 +    /* BC left borders aren't stored on cols, but the previous column's
   1.362 +       right border is the next one's left border.*/
   1.363 +    //Start with table's left border.
   1.364 +    nscoord lastLeftBorder = aTableFrame->GetContinuousLeftBCBorderWidth();
   1.365 +    for (nsTableColGroupFrame* cgFrame = static_cast<nsTableColGroupFrame*>(colGroupList.FirstChild());
   1.366 +         cgFrame; cgFrame = static_cast<nsTableColGroupFrame*>(cgFrame->GetNextSibling())) {
   1.367 +
   1.368 +      if (cgFrame->GetColCount() < 1) {
   1.369 +        //No columns, no cells, so no need for data
   1.370 +        continue;
   1.371 +      }
   1.372 +
   1.373 +      /*Create data struct for column group*/
   1.374 +      cgData = new TableBackgroundData;
   1.375 +      if (!cgData) return NS_ERROR_OUT_OF_MEMORY;
   1.376 +      cgData->SetFull(cgFrame);
   1.377 +      if (mIsBorderCollapse && cgData->ShouldSetBCBorder()) {
   1.378 +        border.left = lastLeftBorder;
   1.379 +        cgFrame->GetContinuousBCBorderWidth(border);
   1.380 +        nsresult rv = cgData->SetBCBorder(border, this);
   1.381 +        if (NS_FAILED(rv)) {
   1.382 +          cgData->Destroy(mPresContext);
   1.383 +          delete cgData;
   1.384 +          return rv;
   1.385 +        }
   1.386 +      }
   1.387 +
   1.388 +      // Boolean that indicates whether mCols took ownership of cgData
   1.389 +      bool cgDataOwnershipTaken = false;
   1.390 +      
   1.391 +      /*Loop over columns in this colgroup*/
   1.392 +      for (nsTableColFrame* col = cgFrame->GetFirstColumn(); col;
   1.393 +           col = static_cast<nsTableColFrame*>(col->GetNextSibling())) {
   1.394 +        /*Create data struct for column*/
   1.395 +        uint32_t colIndex = col->GetColIndex();
   1.396 +        NS_ASSERTION(colIndex < mNumCols, "prevent array boundary violation");
   1.397 +        if (mNumCols <= colIndex)
   1.398 +          break;
   1.399 +        mCols[colIndex].mCol.SetFull(col);
   1.400 +        //Bring column mRect into table's coord system
   1.401 +        mCols[colIndex].mCol.mRect.MoveBy(cgData->mRect.x, cgData->mRect.y);
   1.402 +        //link to parent colgroup's data
   1.403 +        mCols[colIndex].mColGroup = cgData;
   1.404 +        cgDataOwnershipTaken = true;
   1.405 +        if (mIsBorderCollapse) {
   1.406 +          border.left = lastLeftBorder;
   1.407 +          lastLeftBorder = col->GetContinuousBCBorderWidth(border);
   1.408 +          if (mCols[colIndex].mCol.ShouldSetBCBorder()) {
   1.409 +            nsresult rv = mCols[colIndex].mCol.SetBCBorder(border, this);
   1.410 +            if (NS_FAILED(rv)) return rv;
   1.411 +          }
   1.412 +        }
   1.413 +      }
   1.414 +
   1.415 +      if (!cgDataOwnershipTaken) {
   1.416 +        cgData->Destroy(mPresContext);
   1.417 +        delete cgData;
   1.418 +      }
   1.419 +    }
   1.420 +  }
   1.421 +
   1.422 +  for (uint32_t i = 0; i < rowGroups.Length(); i++) {
   1.423 +    nsTableRowGroupFrame* rg = rowGroups[i];
   1.424 +    mRowGroup.SetFrame(rg);
   1.425 +    // Need to compute the right rect via GetOffsetTo, since the row
   1.426 +    // group may not be a child of the table.
   1.427 +    mRowGroup.mRect.MoveTo(rg->GetOffsetTo(aTableFrame));
   1.428 +    if (mRowGroup.mRect.Intersects(mDirtyRect - mRenderPt)) {
   1.429 +      nsresult rv = PaintRowGroup(rg, rg->IsPseudoStackingContextFromStyle());
   1.430 +      if (NS_FAILED(rv)) return rv;
   1.431 +    }
   1.432 +  }
   1.433 +  return NS_OK;
   1.434 +}
   1.435 +
   1.436 +nsresult
   1.437 +TableBackgroundPainter::PaintRowGroup(nsTableRowGroupFrame* aFrame,
   1.438 +                                      bool                  aPassThrough)
   1.439 +{
   1.440 +  NS_PRECONDITION(aFrame, "null frame");
   1.441 +
   1.442 +  if (!mRowGroup.mFrame) {
   1.443 +    mRowGroup.SetFrame(aFrame);
   1.444 +  }
   1.445 +
   1.446 +  nsTableRowFrame* firstRow = aFrame->GetFirstRow();
   1.447 +
   1.448 +  /* Load row group data */
   1.449 +  if (!aPassThrough) {
   1.450 +    mRowGroup.SetData();
   1.451 +    if (mIsBorderCollapse && mRowGroup.ShouldSetBCBorder()) {
   1.452 +      nsMargin border;
   1.453 +      if (firstRow) {
   1.454 +        //pick up first row's top border (= rg top border)
   1.455 +        firstRow->GetContinuousBCBorderWidth(border);
   1.456 +        /* (row group doesn't store its top border) */
   1.457 +      }
   1.458 +      //overwrite sides+bottom borders with rg's own
   1.459 +      aFrame->GetContinuousBCBorderWidth(border);
   1.460 +      nsresult res = mRowGroup.SetBCBorder(border, this);
   1.461 +      if (!NS_SUCCEEDED(res)) {
   1.462 +        return res;
   1.463 +      }
   1.464 +    }
   1.465 +    aPassThrough = !mRowGroup.IsVisible();
   1.466 +  }
   1.467 +
   1.468 +  /* translate everything into row group coord system*/
   1.469 +  if (eOrigin_TableRowGroup != mOrigin) {
   1.470 +    TranslateContext(mRowGroup.mRect.x, mRowGroup.mRect.y);
   1.471 +  }
   1.472 +  nsRect rgRect = mRowGroup.mRect;
   1.473 +  mRowGroup.mRect.MoveTo(0, 0);
   1.474 +
   1.475 +  /* Find the right row to start with */
   1.476 +  nscoord ignored; // We don't care about overflow above, since what we really
   1.477 +                   // care about are backgrounds and overflow above doesn't
   1.478 +                   // correspond to backgrounds, since cells can't span up from
   1.479 +                   // their originating row.  We do care about overflow below,
   1.480 +                   // however, since that can be due to rowspans.
   1.481 +
   1.482 +  // Note that mDirtyRect  - mRenderPt is guaranteed to be in the row
   1.483 +  // group's coordinate system here, so passing its .y to
   1.484 +  // GetFirstRowContaining is ok.
   1.485 +  nsIFrame* cursor = aFrame->GetFirstRowContaining(mDirtyRect.y - mRenderPt.y, &ignored);
   1.486 +
   1.487 +  // Sadly, it seems like there may be non-row frames in there... or something?
   1.488 +  // There are certainly null-checks in GetFirstRow() and GetNextRow().  :(
   1.489 +  while (cursor && cursor->GetType() != nsGkAtoms::tableRowFrame) {
   1.490 +    cursor = cursor->GetNextSibling();
   1.491 +  }
   1.492 +
   1.493 +  // It's OK if cursor is null here.
   1.494 +  nsTableRowFrame* row = static_cast<nsTableRowFrame*>(cursor);  
   1.495 +  if (!row) {
   1.496 +    // No useful cursor; just start at the top.  Don't bother to set up a
   1.497 +    // cursor; if we've gotten this far then we've already built the display
   1.498 +    // list for the rowgroup, so not having a cursor means that there's some
   1.499 +    // good reason we don't have a cursor and we shouldn't create one here.
   1.500 +    row = firstRow;
   1.501 +  }
   1.502 +  
   1.503 +  /* Finally paint */
   1.504 +  for (; row; row = row->GetNextRow()) {
   1.505 +    mRow.SetFrame(row);
   1.506 +    if (mDirtyRect.YMost() - mRenderPt.y < mRow.mRect.y) { // Intersect wouldn't handle
   1.507 +                                             // rowspans.
   1.508 +
   1.509 +      // All done; cells originating in later rows can't intersect mDirtyRect.
   1.510 +      break;
   1.511 +    }
   1.512 +    
   1.513 +    nsresult rv = PaintRow(row, aPassThrough || row->IsPseudoStackingContextFromStyle());
   1.514 +    if (NS_FAILED(rv)) return rv;
   1.515 +  }
   1.516 +
   1.517 +  /* translate back into table coord system */
   1.518 +  if (eOrigin_TableRowGroup != mOrigin) {
   1.519 +    TranslateContext(-rgRect.x, -rgRect.y);
   1.520 +  }
   1.521 +  
   1.522 +  /* unload rg data */
   1.523 +  mRowGroup.Clear();
   1.524 +
   1.525 +  return NS_OK;
   1.526 +}
   1.527 +
   1.528 +nsresult
   1.529 +TableBackgroundPainter::PaintRow(nsTableRowFrame* aFrame,
   1.530 +                                 bool             aPassThrough)
   1.531 +{
   1.532 +  NS_PRECONDITION(aFrame, "null frame");
   1.533 +
   1.534 +  if (!mRow.mFrame) {
   1.535 +    mRow.SetFrame(aFrame);
   1.536 +  }
   1.537 +
   1.538 +  /* Load row data */
   1.539 +  if (!aPassThrough) {
   1.540 +    mRow.SetData();
   1.541 +    if (mIsBorderCollapse && mRow.ShouldSetBCBorder()) {
   1.542 +      nsMargin border;
   1.543 +      nsTableRowFrame* nextRow = aFrame->GetNextRow();
   1.544 +      if (nextRow) { //outer top below us is inner bottom for us
   1.545 +        border.bottom = nextRow->GetOuterTopContBCBorderWidth();
   1.546 +      }
   1.547 +      else { //acquire rg's bottom border
   1.548 +        nsTableRowGroupFrame* rowGroup = static_cast<nsTableRowGroupFrame*>(aFrame->GetParent());
   1.549 +        rowGroup->GetContinuousBCBorderWidth(border);
   1.550 +      }
   1.551 +      //get the rest of the borders; will overwrite all but bottom
   1.552 +      aFrame->GetContinuousBCBorderWidth(border);
   1.553 +
   1.554 +      nsresult res = mRow.SetBCBorder(border, this);
   1.555 +      if (!NS_SUCCEEDED(res)) {
   1.556 +        return res;
   1.557 +      }
   1.558 +    }
   1.559 +    aPassThrough = !mRow.IsVisible();
   1.560 +  }
   1.561 +
   1.562 +  /* Translate */
   1.563 +  if (eOrigin_TableRow == mOrigin) {
   1.564 +    /* If we originate from the row, then make the row the origin. */
   1.565 +    mRow.mRect.MoveTo(0, 0);
   1.566 +  }
   1.567 +  //else: Use row group's coord system -> no translation necessary
   1.568 +
   1.569 +  for (nsTableCellFrame* cell = aFrame->GetFirstCell(); cell; cell = cell->GetNextCell()) {
   1.570 +    //Translate to use the same coord system as mRow.
   1.571 +    mCellRect = cell->GetRect() + mRow.mRect.TopLeft() + mRenderPt;
   1.572 +    if (mCellRect.Intersects(mDirtyRect)) {
   1.573 +      nsresult rv = PaintCell(cell, aPassThrough || cell->IsPseudoStackingContextFromStyle());
   1.574 +      if (NS_FAILED(rv)) return rv;
   1.575 +    }
   1.576 +  }
   1.577 +
   1.578 +  /* Unload row data */
   1.579 +  mRow.Clear();
   1.580 +  return NS_OK;
   1.581 +}
   1.582 +
   1.583 +nsresult
   1.584 +TableBackgroundPainter::PaintCell(nsTableCellFrame* aCell,
   1.585 +                                  bool aPassSelf)
   1.586 +{
   1.587 +  NS_PRECONDITION(aCell, "null frame");
   1.588 +
   1.589 +  const nsStyleTableBorder* cellTableStyle;
   1.590 +  cellTableStyle = aCell->StyleTableBorder();
   1.591 +  if (!(NS_STYLE_TABLE_EMPTY_CELLS_SHOW == cellTableStyle->mEmptyCells ||
   1.592 +        NS_STYLE_TABLE_EMPTY_CELLS_SHOW_BACKGROUND == cellTableStyle->mEmptyCells)
   1.593 +      && aCell->GetContentEmpty() && !mIsBorderCollapse) {
   1.594 +    return NS_OK;
   1.595 +  }
   1.596 +
   1.597 +  int32_t colIndex;
   1.598 +  aCell->GetColIndex(colIndex);
   1.599 +  NS_ASSERTION(colIndex < int32_t(mNumCols), "prevent array boundary violation");
   1.600 +  if (int32_t(mNumCols) <= colIndex)
   1.601 +    return NS_OK;
   1.602 +
   1.603 +  //Paint column group background
   1.604 +  if (mCols && mCols[colIndex].mColGroup && mCols[colIndex].mColGroup->IsVisible()) {
   1.605 +    nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
   1.606 +                                          mCols[colIndex].mColGroup->mFrame, mDirtyRect,
   1.607 +                                          mCols[colIndex].mColGroup->mRect + mRenderPt,
   1.608 +                                          mCols[colIndex].mColGroup->mFrame->StyleContext(),
   1.609 +                                          *mCols[colIndex].mColGroup->mBorder,
   1.610 +                                          mBGPaintFlags, &mCellRect);
   1.611 +  }
   1.612 +
   1.613 +  //Paint column background
   1.614 +  if (mCols && mCols[colIndex].mCol.IsVisible()) {
   1.615 +    nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
   1.616 +                                          mCols[colIndex].mCol.mFrame, mDirtyRect,
   1.617 +                                          mCols[colIndex].mCol.mRect + mRenderPt,
   1.618 +                                          mCols[colIndex].mCol.mFrame->StyleContext(),
   1.619 +                                          *mCols[colIndex].mCol.mBorder,
   1.620 +                                          mBGPaintFlags, &mCellRect);
   1.621 +  }
   1.622 +
   1.623 +  //Paint row group background
   1.624 +  if (mRowGroup.IsVisible()) {
   1.625 +    nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
   1.626 +                                          mRowGroup.mFrame, mDirtyRect,
   1.627 +                                          mRowGroup.mRect + mRenderPt,
   1.628 +                                          mRowGroup.mFrame->StyleContext(),
   1.629 +                                          *mRowGroup.mBorder,
   1.630 +                                          mBGPaintFlags, &mCellRect);
   1.631 +  }
   1.632 +
   1.633 +  //Paint row background
   1.634 +  if (mRow.IsVisible()) {
   1.635 +    nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
   1.636 +                                          mRow.mFrame, mDirtyRect,
   1.637 +                                          mRow.mRect + mRenderPt,
   1.638 +                                          mRow.mFrame->StyleContext(),
   1.639 +                                          *mRow.mBorder,
   1.640 +                                          mBGPaintFlags, &mCellRect);
   1.641 +  }
   1.642 +
   1.643 +  //Paint cell background in border-collapse unless we're just passing
   1.644 +  if (mIsBorderCollapse && !aPassSelf) {
   1.645 +    aCell->PaintCellBackground(mRenderingContext, mDirtyRect,
   1.646 +                               mCellRect.TopLeft(), mBGPaintFlags);
   1.647 +  }
   1.648 +
   1.649 +  return NS_OK;
   1.650 +}

mercurial