Fri, 16 Jan 2015 04:50:19 +0100
Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsTableFrame.h"
7 #include "nsTableRowGroupFrame.h"
8 #include "nsTableRowFrame.h"
9 #include "nsTableColGroupFrame.h"
10 #include "nsTableColFrame.h"
11 #include "nsTableCellFrame.h"
12 #include "nsTablePainter.h"
13 #include "nsCSSRendering.h"
14 #include "nsDisplayList.h"
16 /* ~*~ Table Background Painting ~*~
18 Mozilla's Table Background painting follows CSS2.1:17.5.1
19 That section does not, however, describe the effect of
20 borders on background image positioning. What we do is:
22 - in separate borders, the borders are passed in so that
23 their width figures in image positioning, even for rows/cols, which
24 don't have visible borders. This is done to allow authors
25 to position row backgrounds by, for example, aligning the
26 top left corner with the top left padding corner of the
27 top left table cell in the row in cases where all cells
28 have consistent border widths. If we didn't honor these
29 invisible borders, there would be no way to align
30 backgrounds with the padding edges, and designs would be
31 lost underneath the border.
33 - in collapsing borders, because the borders collapse, we
34 use the -continuous border- width to synthesize a border
35 style and pass that in instead of using the element's
36 assigned style directly.
38 The continuous border on a given edge of an element is
39 the collapse of all borders guaranteed to be continuous
40 along that edge. Cell borders are ignored (because, for
41 example, setting a thick border on the leftmost cell
42 should not shift the row background over; this way a
43 striped background set on <tr> will line up across rows
44 even if the cells are assigned arbitrary border widths.
46 For example, the continuous border on the top edge of a
47 row group is the collapse of any row group, row, and
48 table borders involved. (The first row group's top would
49 be [table-top + row group top + first row top]. It's bottom
50 would be [row group bottom + last row bottom + next row
51 top + next row group top].)
52 The top edge of a column group likewise includes the
53 table top, row group top, and first row top borders. However,
54 it *also* includes its own top border, since that is guaranteed
55 to be continuous. It does not include column borders because
56 those are not guaranteed to be continuous: there may be two
57 columns with different borders in a single column group.
59 An alternative would be to define the continuous border as
60 [table? + row group + row] for horizontal
61 [table? + col group + col] for vertical
62 This makes it easier to line up backgrounds across elements
63 despite varying border widths, but it does not give much
64 flexibility in aligning /to/ those border widths.
65 */
68 /* ~*~ TableBackgroundPainter ~*~
70 The TableBackgroundPainter is created and destroyed in one painting call.
71 Its principal function is PaintTable, which paints all table element
72 backgrounds. The initial code in that method sets up an array of column
73 data that caches the background styles and the border sizes for the
74 columns and colgroups in TableBackgroundData structs in mCols. Data for
75 BC borders are calculated and stashed in a synthesized border style struct
76 in the data struct since collapsed borders aren't the same width as style-
77 assigned borders. The data struct optimizes by only doing this if there's
78 an image background; otherwise we don't care. //XXX should also check background-origin
79 The class then loops through the row groups, rows, and cells. It uses
80 the mRowGroup and mRow TableBackgroundData structs to cache data for
81 the current frame in the loop. At the cell level, it paints the backgrounds,
82 one over the other, inside the cell rect.
84 The exception to this pattern is when a table element creates a (pseudo)
85 stacking context. Elements with stacking contexts (e.g., 'opacity' applied)
86 are <dfn>passed through</dfn>, which means their data (and their
87 descendants' data) are not cached. The full loop is still executed, however,
88 so that underlying layers can get painted at the cell level.
90 The TableBackgroundPainter is then destroyed.
92 Elements with stacking contexts set up their own painter to finish the
93 painting process, since they were skipped. They call the appropriate
94 sub-part of the loop (e.g. PaintRow) which will paint the frame and
95 descendants. Note that it is permissible according to CSS2.1 to ignore'
96 'position:relative' (and implicitly, 'opacity') on table parts so that
97 table parts can never create stacking contexts; if we want to, we can
98 implement that, and then we won't have to deal with TableBackgroundPainter
99 being used anywhere but from the nsTableFrame.
101 XXX views are going
102 */
104 TableBackgroundPainter::TableBackgroundData::TableBackgroundData()
105 : mFrame(nullptr),
106 mVisible(false),
107 mBorder(nullptr),
108 mSynthBorder(nullptr)
109 {
110 MOZ_COUNT_CTOR(TableBackgroundData);
111 }
113 TableBackgroundPainter::TableBackgroundData::~TableBackgroundData()
114 {
115 NS_ASSERTION(!mSynthBorder, "must call Destroy before dtor");
116 MOZ_COUNT_DTOR(TableBackgroundData);
117 }
119 void
120 TableBackgroundPainter::TableBackgroundData::Destroy(nsPresContext* aPresContext)
121 {
122 NS_PRECONDITION(aPresContext, "null prescontext");
123 if (mSynthBorder) {
124 mSynthBorder->Destroy(aPresContext);
125 mSynthBorder = nullptr;
126 }
127 }
129 void
130 TableBackgroundPainter::TableBackgroundData::Clear()
131 {
132 mRect.SetEmpty();
133 mFrame = nullptr;
134 mBorder = nullptr;
135 mVisible = false;
136 }
138 void
139 TableBackgroundPainter::TableBackgroundData::SetFrame(nsIFrame* aFrame)
140 {
141 NS_PRECONDITION(aFrame, "null frame");
142 mFrame = aFrame;
143 mRect = aFrame->GetRect();
144 }
146 void
147 TableBackgroundPainter::TableBackgroundData::SetData()
148 {
149 NS_PRECONDITION(mFrame, "null frame");
150 if (mFrame->IsVisibleForPainting()) {
151 mVisible = true;
152 mBorder = mFrame->StyleBorder();
153 }
154 }
156 void
157 TableBackgroundPainter::TableBackgroundData::SetFull(nsIFrame* aFrame)
158 {
159 NS_PRECONDITION(aFrame, "null frame");
160 SetFrame(aFrame);
161 SetData();
162 }
164 inline bool
165 TableBackgroundPainter::TableBackgroundData::ShouldSetBCBorder()
166 {
167 /* we only need accurate border data when positioning background images*/
168 if (!mVisible) {
169 return false;
170 }
172 const nsStyleBackground *bg = mFrame->StyleBackground();
173 NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) {
174 if (!bg->mLayers[i].mImage.IsEmpty())
175 return true;
176 }
177 return false;
178 }
180 nsresult
181 TableBackgroundPainter::TableBackgroundData::SetBCBorder(nsMargin& aBorder,
182 TableBackgroundPainter* aPainter)
183 {
184 NS_PRECONDITION(aPainter, "null painter");
185 if (!mSynthBorder) {
186 mSynthBorder = new (aPainter->mPresContext)
187 nsStyleBorder(aPainter->mZeroBorder);
188 if (!mSynthBorder) return NS_ERROR_OUT_OF_MEMORY;
189 }
191 NS_FOR_CSS_SIDES(side) {
192 mSynthBorder->SetBorderWidth(side, aBorder.Side(side));
193 }
195 mBorder = mSynthBorder;
196 return NS_OK;
197 }
199 TableBackgroundPainter::TableBackgroundPainter(nsTableFrame* aTableFrame,
200 Origin aOrigin,
201 nsPresContext* aPresContext,
202 nsRenderingContext& aRenderingContext,
203 const nsRect& aDirtyRect,
204 const nsPoint& aRenderPt,
205 uint32_t aBGPaintFlags)
206 : mPresContext(aPresContext),
207 mRenderingContext(aRenderingContext),
208 mRenderPt(aRenderPt),
209 mDirtyRect(aDirtyRect),
210 mOrigin(aOrigin),
211 mCols(nullptr),
212 mZeroBorder(aPresContext),
213 mBGPaintFlags(aBGPaintFlags)
214 {
215 MOZ_COUNT_CTOR(TableBackgroundPainter);
217 NS_FOR_CSS_SIDES(side) {
218 mZeroBorder.SetBorderStyle(side, NS_STYLE_BORDER_STYLE_SOLID);
219 mZeroBorder.SetBorderWidth(side, 0);
220 }
222 mIsBorderCollapse = aTableFrame->IsBorderCollapse();
223 #ifdef DEBUG
224 mCompatMode = mPresContext->CompatibilityMode();
225 #endif
226 mNumCols = aTableFrame->GetColCount();
227 }
229 TableBackgroundPainter::~TableBackgroundPainter()
230 {
231 if (mCols) {
232 TableBackgroundData* lastColGroup = nullptr;
233 for (uint32_t i = 0; i < mNumCols; i++) {
234 if (mCols[i].mColGroup != lastColGroup) {
235 lastColGroup = mCols[i].mColGroup;
236 NS_ASSERTION(mCols[i].mColGroup, "colgroup data should not be null - bug 237421");
237 // we need to wallpaper a over zero pointer deref, bug 237421 will have the real fix
238 if(lastColGroup)
239 lastColGroup->Destroy(mPresContext);
240 delete lastColGroup;
241 }
242 mCols[i].mColGroup = nullptr;
243 mCols[i].mCol.Destroy(mPresContext);
244 }
245 delete [] mCols;
246 }
247 mRowGroup.Destroy(mPresContext);
248 mRow.Destroy(mPresContext);
249 MOZ_COUNT_DTOR(TableBackgroundPainter);
250 }
252 nsresult
253 TableBackgroundPainter::PaintTableFrame(nsTableFrame* aTableFrame,
254 nsTableRowGroupFrame* aFirstRowGroup,
255 nsTableRowGroupFrame* aLastRowGroup,
256 const nsMargin& aDeflate)
257 {
258 NS_PRECONDITION(aTableFrame, "null frame");
259 TableBackgroundData tableData;
260 tableData.SetFull(aTableFrame);
261 tableData.mRect.MoveTo(0,0); //using table's coords
262 tableData.mRect.Deflate(aDeflate);
263 if (mIsBorderCollapse && tableData.ShouldSetBCBorder()) {
264 if (aFirstRowGroup && aLastRowGroup && mNumCols > 0) {
265 //only handle non-degenerate tables; we need a more robust BC model
266 //to make degenerate tables' borders reasonable to deal with
267 nsMargin border, tempBorder;
268 nsTableColFrame* colFrame = aTableFrame->GetColFrame(mNumCols - 1);
269 if (colFrame) {
270 colFrame->GetContinuousBCBorderWidth(tempBorder);
271 }
272 border.right = tempBorder.right;
274 aLastRowGroup->GetContinuousBCBorderWidth(tempBorder);
275 border.bottom = tempBorder.bottom;
277 nsTableRowFrame* rowFrame = aFirstRowGroup->GetFirstRow();
278 if (rowFrame) {
279 rowFrame->GetContinuousBCBorderWidth(tempBorder);
280 border.top = tempBorder.top;
281 }
283 border.left = aTableFrame->GetContinuousLeftBCBorderWidth();
285 nsresult rv = tableData.SetBCBorder(border, this);
286 if (NS_FAILED(rv)) {
287 tableData.Destroy(mPresContext);
288 return rv;
289 }
290 }
291 }
292 if (tableData.IsVisible()) {
293 nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
294 tableData.mFrame, mDirtyRect,
295 tableData.mRect + mRenderPt,
296 tableData.mFrame->StyleContext(),
297 *tableData.mBorder,
298 mBGPaintFlags);
299 }
300 tableData.Destroy(mPresContext);
301 return NS_OK;
302 }
304 void
305 TableBackgroundPainter::TranslateContext(nscoord aDX,
306 nscoord aDY)
307 {
308 mRenderPt += nsPoint(aDX, aDY);
309 if (mCols) {
310 TableBackgroundData* lastColGroup = nullptr;
311 for (uint32_t i = 0; i < mNumCols; i++) {
312 mCols[i].mCol.mRect.MoveBy(-aDX, -aDY);
313 if (lastColGroup != mCols[i].mColGroup) {
314 NS_ASSERTION(mCols[i].mColGroup, "colgroup data should not be null - bug 237421");
315 // we need to wallpaper a over zero pointer deref, bug 237421 will have the real fix
316 if (!mCols[i].mColGroup)
317 return;
318 mCols[i].mColGroup->mRect.MoveBy(-aDX, -aDY);
319 lastColGroup = mCols[i].mColGroup;
320 }
321 }
322 }
323 }
325 nsresult
326 TableBackgroundPainter::PaintTable(nsTableFrame* aTableFrame,
327 const nsMargin& aDeflate,
328 bool aPaintTableBackground)
329 {
330 NS_PRECONDITION(aTableFrame, "null table frame");
332 nsTableFrame::RowGroupArray rowGroups;
333 aTableFrame->OrderRowGroups(rowGroups);
335 if (rowGroups.Length() < 1) { //degenerate case
336 if (aPaintTableBackground) {
337 PaintTableFrame(aTableFrame, nullptr, nullptr, nsMargin(0,0,0,0));
338 }
339 /* No cells; nothing else to paint */
340 return NS_OK;
341 }
343 if (aPaintTableBackground) {
344 PaintTableFrame(aTableFrame, rowGroups[0], rowGroups[rowGroups.Length() - 1],
345 aDeflate);
346 }
348 /*Set up column background/border data*/
349 if (mNumCols > 0) {
350 nsFrameList& colGroupList = aTableFrame->GetColGroups();
351 NS_ASSERTION(colGroupList.FirstChild(), "table should have at least one colgroup");
353 mCols = new ColData[mNumCols];
354 if (!mCols) return NS_ERROR_OUT_OF_MEMORY;
356 TableBackgroundData* cgData = nullptr;
357 nsMargin border;
358 /* BC left borders aren't stored on cols, but the previous column's
359 right border is the next one's left border.*/
360 //Start with table's left border.
361 nscoord lastLeftBorder = aTableFrame->GetContinuousLeftBCBorderWidth();
362 for (nsTableColGroupFrame* cgFrame = static_cast<nsTableColGroupFrame*>(colGroupList.FirstChild());
363 cgFrame; cgFrame = static_cast<nsTableColGroupFrame*>(cgFrame->GetNextSibling())) {
365 if (cgFrame->GetColCount() < 1) {
366 //No columns, no cells, so no need for data
367 continue;
368 }
370 /*Create data struct for column group*/
371 cgData = new TableBackgroundData;
372 if (!cgData) return NS_ERROR_OUT_OF_MEMORY;
373 cgData->SetFull(cgFrame);
374 if (mIsBorderCollapse && cgData->ShouldSetBCBorder()) {
375 border.left = lastLeftBorder;
376 cgFrame->GetContinuousBCBorderWidth(border);
377 nsresult rv = cgData->SetBCBorder(border, this);
378 if (NS_FAILED(rv)) {
379 cgData->Destroy(mPresContext);
380 delete cgData;
381 return rv;
382 }
383 }
385 // Boolean that indicates whether mCols took ownership of cgData
386 bool cgDataOwnershipTaken = false;
388 /*Loop over columns in this colgroup*/
389 for (nsTableColFrame* col = cgFrame->GetFirstColumn(); col;
390 col = static_cast<nsTableColFrame*>(col->GetNextSibling())) {
391 /*Create data struct for column*/
392 uint32_t colIndex = col->GetColIndex();
393 NS_ASSERTION(colIndex < mNumCols, "prevent array boundary violation");
394 if (mNumCols <= colIndex)
395 break;
396 mCols[colIndex].mCol.SetFull(col);
397 //Bring column mRect into table's coord system
398 mCols[colIndex].mCol.mRect.MoveBy(cgData->mRect.x, cgData->mRect.y);
399 //link to parent colgroup's data
400 mCols[colIndex].mColGroup = cgData;
401 cgDataOwnershipTaken = true;
402 if (mIsBorderCollapse) {
403 border.left = lastLeftBorder;
404 lastLeftBorder = col->GetContinuousBCBorderWidth(border);
405 if (mCols[colIndex].mCol.ShouldSetBCBorder()) {
406 nsresult rv = mCols[colIndex].mCol.SetBCBorder(border, this);
407 if (NS_FAILED(rv)) return rv;
408 }
409 }
410 }
412 if (!cgDataOwnershipTaken) {
413 cgData->Destroy(mPresContext);
414 delete cgData;
415 }
416 }
417 }
419 for (uint32_t i = 0; i < rowGroups.Length(); i++) {
420 nsTableRowGroupFrame* rg = rowGroups[i];
421 mRowGroup.SetFrame(rg);
422 // Need to compute the right rect via GetOffsetTo, since the row
423 // group may not be a child of the table.
424 mRowGroup.mRect.MoveTo(rg->GetOffsetTo(aTableFrame));
425 if (mRowGroup.mRect.Intersects(mDirtyRect - mRenderPt)) {
426 nsresult rv = PaintRowGroup(rg, rg->IsPseudoStackingContextFromStyle());
427 if (NS_FAILED(rv)) return rv;
428 }
429 }
430 return NS_OK;
431 }
433 nsresult
434 TableBackgroundPainter::PaintRowGroup(nsTableRowGroupFrame* aFrame,
435 bool aPassThrough)
436 {
437 NS_PRECONDITION(aFrame, "null frame");
439 if (!mRowGroup.mFrame) {
440 mRowGroup.SetFrame(aFrame);
441 }
443 nsTableRowFrame* firstRow = aFrame->GetFirstRow();
445 /* Load row group data */
446 if (!aPassThrough) {
447 mRowGroup.SetData();
448 if (mIsBorderCollapse && mRowGroup.ShouldSetBCBorder()) {
449 nsMargin border;
450 if (firstRow) {
451 //pick up first row's top border (= rg top border)
452 firstRow->GetContinuousBCBorderWidth(border);
453 /* (row group doesn't store its top border) */
454 }
455 //overwrite sides+bottom borders with rg's own
456 aFrame->GetContinuousBCBorderWidth(border);
457 nsresult res = mRowGroup.SetBCBorder(border, this);
458 if (!NS_SUCCEEDED(res)) {
459 return res;
460 }
461 }
462 aPassThrough = !mRowGroup.IsVisible();
463 }
465 /* translate everything into row group coord system*/
466 if (eOrigin_TableRowGroup != mOrigin) {
467 TranslateContext(mRowGroup.mRect.x, mRowGroup.mRect.y);
468 }
469 nsRect rgRect = mRowGroup.mRect;
470 mRowGroup.mRect.MoveTo(0, 0);
472 /* Find the right row to start with */
473 nscoord ignored; // We don't care about overflow above, since what we really
474 // care about are backgrounds and overflow above doesn't
475 // correspond to backgrounds, since cells can't span up from
476 // their originating row. We do care about overflow below,
477 // however, since that can be due to rowspans.
479 // Note that mDirtyRect - mRenderPt is guaranteed to be in the row
480 // group's coordinate system here, so passing its .y to
481 // GetFirstRowContaining is ok.
482 nsIFrame* cursor = aFrame->GetFirstRowContaining(mDirtyRect.y - mRenderPt.y, &ignored);
484 // Sadly, it seems like there may be non-row frames in there... or something?
485 // There are certainly null-checks in GetFirstRow() and GetNextRow(). :(
486 while (cursor && cursor->GetType() != nsGkAtoms::tableRowFrame) {
487 cursor = cursor->GetNextSibling();
488 }
490 // It's OK if cursor is null here.
491 nsTableRowFrame* row = static_cast<nsTableRowFrame*>(cursor);
492 if (!row) {
493 // No useful cursor; just start at the top. Don't bother to set up a
494 // cursor; if we've gotten this far then we've already built the display
495 // list for the rowgroup, so not having a cursor means that there's some
496 // good reason we don't have a cursor and we shouldn't create one here.
497 row = firstRow;
498 }
500 /* Finally paint */
501 for (; row; row = row->GetNextRow()) {
502 mRow.SetFrame(row);
503 if (mDirtyRect.YMost() - mRenderPt.y < mRow.mRect.y) { // Intersect wouldn't handle
504 // rowspans.
506 // All done; cells originating in later rows can't intersect mDirtyRect.
507 break;
508 }
510 nsresult rv = PaintRow(row, aPassThrough || row->IsPseudoStackingContextFromStyle());
511 if (NS_FAILED(rv)) return rv;
512 }
514 /* translate back into table coord system */
515 if (eOrigin_TableRowGroup != mOrigin) {
516 TranslateContext(-rgRect.x, -rgRect.y);
517 }
519 /* unload rg data */
520 mRowGroup.Clear();
522 return NS_OK;
523 }
525 nsresult
526 TableBackgroundPainter::PaintRow(nsTableRowFrame* aFrame,
527 bool aPassThrough)
528 {
529 NS_PRECONDITION(aFrame, "null frame");
531 if (!mRow.mFrame) {
532 mRow.SetFrame(aFrame);
533 }
535 /* Load row data */
536 if (!aPassThrough) {
537 mRow.SetData();
538 if (mIsBorderCollapse && mRow.ShouldSetBCBorder()) {
539 nsMargin border;
540 nsTableRowFrame* nextRow = aFrame->GetNextRow();
541 if (nextRow) { //outer top below us is inner bottom for us
542 border.bottom = nextRow->GetOuterTopContBCBorderWidth();
543 }
544 else { //acquire rg's bottom border
545 nsTableRowGroupFrame* rowGroup = static_cast<nsTableRowGroupFrame*>(aFrame->GetParent());
546 rowGroup->GetContinuousBCBorderWidth(border);
547 }
548 //get the rest of the borders; will overwrite all but bottom
549 aFrame->GetContinuousBCBorderWidth(border);
551 nsresult res = mRow.SetBCBorder(border, this);
552 if (!NS_SUCCEEDED(res)) {
553 return res;
554 }
555 }
556 aPassThrough = !mRow.IsVisible();
557 }
559 /* Translate */
560 if (eOrigin_TableRow == mOrigin) {
561 /* If we originate from the row, then make the row the origin. */
562 mRow.mRect.MoveTo(0, 0);
563 }
564 //else: Use row group's coord system -> no translation necessary
566 for (nsTableCellFrame* cell = aFrame->GetFirstCell(); cell; cell = cell->GetNextCell()) {
567 //Translate to use the same coord system as mRow.
568 mCellRect = cell->GetRect() + mRow.mRect.TopLeft() + mRenderPt;
569 if (mCellRect.Intersects(mDirtyRect)) {
570 nsresult rv = PaintCell(cell, aPassThrough || cell->IsPseudoStackingContextFromStyle());
571 if (NS_FAILED(rv)) return rv;
572 }
573 }
575 /* Unload row data */
576 mRow.Clear();
577 return NS_OK;
578 }
580 nsresult
581 TableBackgroundPainter::PaintCell(nsTableCellFrame* aCell,
582 bool aPassSelf)
583 {
584 NS_PRECONDITION(aCell, "null frame");
586 const nsStyleTableBorder* cellTableStyle;
587 cellTableStyle = aCell->StyleTableBorder();
588 if (!(NS_STYLE_TABLE_EMPTY_CELLS_SHOW == cellTableStyle->mEmptyCells ||
589 NS_STYLE_TABLE_EMPTY_CELLS_SHOW_BACKGROUND == cellTableStyle->mEmptyCells)
590 && aCell->GetContentEmpty() && !mIsBorderCollapse) {
591 return NS_OK;
592 }
594 int32_t colIndex;
595 aCell->GetColIndex(colIndex);
596 NS_ASSERTION(colIndex < int32_t(mNumCols), "prevent array boundary violation");
597 if (int32_t(mNumCols) <= colIndex)
598 return NS_OK;
600 //Paint column group background
601 if (mCols && mCols[colIndex].mColGroup && mCols[colIndex].mColGroup->IsVisible()) {
602 nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
603 mCols[colIndex].mColGroup->mFrame, mDirtyRect,
604 mCols[colIndex].mColGroup->mRect + mRenderPt,
605 mCols[colIndex].mColGroup->mFrame->StyleContext(),
606 *mCols[colIndex].mColGroup->mBorder,
607 mBGPaintFlags, &mCellRect);
608 }
610 //Paint column background
611 if (mCols && mCols[colIndex].mCol.IsVisible()) {
612 nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
613 mCols[colIndex].mCol.mFrame, mDirtyRect,
614 mCols[colIndex].mCol.mRect + mRenderPt,
615 mCols[colIndex].mCol.mFrame->StyleContext(),
616 *mCols[colIndex].mCol.mBorder,
617 mBGPaintFlags, &mCellRect);
618 }
620 //Paint row group background
621 if (mRowGroup.IsVisible()) {
622 nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
623 mRowGroup.mFrame, mDirtyRect,
624 mRowGroup.mRect + mRenderPt,
625 mRowGroup.mFrame->StyleContext(),
626 *mRowGroup.mBorder,
627 mBGPaintFlags, &mCellRect);
628 }
630 //Paint row background
631 if (mRow.IsVisible()) {
632 nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
633 mRow.mFrame, mDirtyRect,
634 mRow.mRect + mRenderPt,
635 mRow.mFrame->StyleContext(),
636 *mRow.mBorder,
637 mBGPaintFlags, &mCellRect);
638 }
640 //Paint cell background in border-collapse unless we're just passing
641 if (mIsBorderCollapse && !aPassSelf) {
642 aCell->PaintCellBackground(mRenderingContext, mDirtyRect,
643 mCellRect.TopLeft(), mBGPaintFlags);
644 }
646 return NS_OK;
647 }