|
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/. */ |
|
5 |
|
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" |
|
15 |
|
16 /* ~*~ Table Background Painting ~*~ |
|
17 |
|
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: |
|
21 |
|
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. |
|
32 |
|
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. |
|
37 |
|
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. |
|
45 |
|
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. |
|
58 |
|
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 */ |
|
66 |
|
67 |
|
68 /* ~*~ TableBackgroundPainter ~*~ |
|
69 |
|
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. |
|
83 |
|
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. |
|
89 |
|
90 The TableBackgroundPainter is then destroyed. |
|
91 |
|
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. |
|
100 |
|
101 XXX views are going |
|
102 */ |
|
103 |
|
104 TableBackgroundPainter::TableBackgroundData::TableBackgroundData() |
|
105 : mFrame(nullptr), |
|
106 mVisible(false), |
|
107 mBorder(nullptr), |
|
108 mSynthBorder(nullptr) |
|
109 { |
|
110 MOZ_COUNT_CTOR(TableBackgroundData); |
|
111 } |
|
112 |
|
113 TableBackgroundPainter::TableBackgroundData::~TableBackgroundData() |
|
114 { |
|
115 NS_ASSERTION(!mSynthBorder, "must call Destroy before dtor"); |
|
116 MOZ_COUNT_DTOR(TableBackgroundData); |
|
117 } |
|
118 |
|
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 } |
|
128 |
|
129 void |
|
130 TableBackgroundPainter::TableBackgroundData::Clear() |
|
131 { |
|
132 mRect.SetEmpty(); |
|
133 mFrame = nullptr; |
|
134 mBorder = nullptr; |
|
135 mVisible = false; |
|
136 } |
|
137 |
|
138 void |
|
139 TableBackgroundPainter::TableBackgroundData::SetFrame(nsIFrame* aFrame) |
|
140 { |
|
141 NS_PRECONDITION(aFrame, "null frame"); |
|
142 mFrame = aFrame; |
|
143 mRect = aFrame->GetRect(); |
|
144 } |
|
145 |
|
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 } |
|
155 |
|
156 void |
|
157 TableBackgroundPainter::TableBackgroundData::SetFull(nsIFrame* aFrame) |
|
158 { |
|
159 NS_PRECONDITION(aFrame, "null frame"); |
|
160 SetFrame(aFrame); |
|
161 SetData(); |
|
162 } |
|
163 |
|
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 } |
|
171 |
|
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 } |
|
179 |
|
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 } |
|
190 |
|
191 NS_FOR_CSS_SIDES(side) { |
|
192 mSynthBorder->SetBorderWidth(side, aBorder.Side(side)); |
|
193 } |
|
194 |
|
195 mBorder = mSynthBorder; |
|
196 return NS_OK; |
|
197 } |
|
198 |
|
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); |
|
216 |
|
217 NS_FOR_CSS_SIDES(side) { |
|
218 mZeroBorder.SetBorderStyle(side, NS_STYLE_BORDER_STYLE_SOLID); |
|
219 mZeroBorder.SetBorderWidth(side, 0); |
|
220 } |
|
221 |
|
222 mIsBorderCollapse = aTableFrame->IsBorderCollapse(); |
|
223 #ifdef DEBUG |
|
224 mCompatMode = mPresContext->CompatibilityMode(); |
|
225 #endif |
|
226 mNumCols = aTableFrame->GetColCount(); |
|
227 } |
|
228 |
|
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 } |
|
251 |
|
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; |
|
273 |
|
274 aLastRowGroup->GetContinuousBCBorderWidth(tempBorder); |
|
275 border.bottom = tempBorder.bottom; |
|
276 |
|
277 nsTableRowFrame* rowFrame = aFirstRowGroup->GetFirstRow(); |
|
278 if (rowFrame) { |
|
279 rowFrame->GetContinuousBCBorderWidth(tempBorder); |
|
280 border.top = tempBorder.top; |
|
281 } |
|
282 |
|
283 border.left = aTableFrame->GetContinuousLeftBCBorderWidth(); |
|
284 |
|
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 } |
|
303 |
|
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 } |
|
324 |
|
325 nsresult |
|
326 TableBackgroundPainter::PaintTable(nsTableFrame* aTableFrame, |
|
327 const nsMargin& aDeflate, |
|
328 bool aPaintTableBackground) |
|
329 { |
|
330 NS_PRECONDITION(aTableFrame, "null table frame"); |
|
331 |
|
332 nsTableFrame::RowGroupArray rowGroups; |
|
333 aTableFrame->OrderRowGroups(rowGroups); |
|
334 |
|
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 } |
|
342 |
|
343 if (aPaintTableBackground) { |
|
344 PaintTableFrame(aTableFrame, rowGroups[0], rowGroups[rowGroups.Length() - 1], |
|
345 aDeflate); |
|
346 } |
|
347 |
|
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"); |
|
352 |
|
353 mCols = new ColData[mNumCols]; |
|
354 if (!mCols) return NS_ERROR_OUT_OF_MEMORY; |
|
355 |
|
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())) { |
|
364 |
|
365 if (cgFrame->GetColCount() < 1) { |
|
366 //No columns, no cells, so no need for data |
|
367 continue; |
|
368 } |
|
369 |
|
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 } |
|
384 |
|
385 // Boolean that indicates whether mCols took ownership of cgData |
|
386 bool cgDataOwnershipTaken = false; |
|
387 |
|
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 } |
|
411 |
|
412 if (!cgDataOwnershipTaken) { |
|
413 cgData->Destroy(mPresContext); |
|
414 delete cgData; |
|
415 } |
|
416 } |
|
417 } |
|
418 |
|
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 } |
|
432 |
|
433 nsresult |
|
434 TableBackgroundPainter::PaintRowGroup(nsTableRowGroupFrame* aFrame, |
|
435 bool aPassThrough) |
|
436 { |
|
437 NS_PRECONDITION(aFrame, "null frame"); |
|
438 |
|
439 if (!mRowGroup.mFrame) { |
|
440 mRowGroup.SetFrame(aFrame); |
|
441 } |
|
442 |
|
443 nsTableRowFrame* firstRow = aFrame->GetFirstRow(); |
|
444 |
|
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 } |
|
464 |
|
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); |
|
471 |
|
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. |
|
478 |
|
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); |
|
483 |
|
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 } |
|
489 |
|
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 } |
|
499 |
|
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. |
|
505 |
|
506 // All done; cells originating in later rows can't intersect mDirtyRect. |
|
507 break; |
|
508 } |
|
509 |
|
510 nsresult rv = PaintRow(row, aPassThrough || row->IsPseudoStackingContextFromStyle()); |
|
511 if (NS_FAILED(rv)) return rv; |
|
512 } |
|
513 |
|
514 /* translate back into table coord system */ |
|
515 if (eOrigin_TableRowGroup != mOrigin) { |
|
516 TranslateContext(-rgRect.x, -rgRect.y); |
|
517 } |
|
518 |
|
519 /* unload rg data */ |
|
520 mRowGroup.Clear(); |
|
521 |
|
522 return NS_OK; |
|
523 } |
|
524 |
|
525 nsresult |
|
526 TableBackgroundPainter::PaintRow(nsTableRowFrame* aFrame, |
|
527 bool aPassThrough) |
|
528 { |
|
529 NS_PRECONDITION(aFrame, "null frame"); |
|
530 |
|
531 if (!mRow.mFrame) { |
|
532 mRow.SetFrame(aFrame); |
|
533 } |
|
534 |
|
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); |
|
550 |
|
551 nsresult res = mRow.SetBCBorder(border, this); |
|
552 if (!NS_SUCCEEDED(res)) { |
|
553 return res; |
|
554 } |
|
555 } |
|
556 aPassThrough = !mRow.IsVisible(); |
|
557 } |
|
558 |
|
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 |
|
565 |
|
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 } |
|
574 |
|
575 /* Unload row data */ |
|
576 mRow.Clear(); |
|
577 return NS_OK; |
|
578 } |
|
579 |
|
580 nsresult |
|
581 TableBackgroundPainter::PaintCell(nsTableCellFrame* aCell, |
|
582 bool aPassSelf) |
|
583 { |
|
584 NS_PRECONDITION(aCell, "null frame"); |
|
585 |
|
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 } |
|
593 |
|
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; |
|
599 |
|
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 } |
|
609 |
|
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 } |
|
619 |
|
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 } |
|
629 |
|
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 } |
|
639 |
|
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 } |
|
645 |
|
646 return NS_OK; |
|
647 } |