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 +}