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