Back to index

lightning-sunbird  0.9+nobinonly
nsTablePainter.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is TableBackgroundPainter implementation.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Elika J. Etemad ("fantasai") <fantasai@inkedblade.net>.
00019  * Portions created by the Initial Developer are Copyright (C) 2004
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsTableFrame.h"
00039 #include "nsTableRowGroupFrame.h"
00040 #include "nsTableRowFrame.h"
00041 #include "nsTableColGroupFrame.h"
00042 #include "nsTableColFrame.h"
00043 #include "nsTableCellFrame.h"
00044 #include "nsTablePainter.h"
00045 #include "nsCSSRendering.h"
00046 
00047 /* ~*~ Table Background Painting ~*~
00048 
00049    Mozilla's Table Background painting follows CSS2.1:17.5.1
00050    That section does not, however, describe the effect of
00051    borders on background image positioning. What we do is:
00052 
00053      - in separate borders, the borders are passed in so that
00054        their width figures in image positioning, even for rows/cols, which
00055        don't have visible borders. This is done to allow authors
00056        to position row backgrounds by, for example, aligning the
00057        top left corner with the top left padding corner of the
00058        top left table cell in the row in cases where all cells
00059        have consistent border widths. If we didn't honor these
00060        invisible borders, there would be no way to align
00061        backgrounds with the padding edges, and designs would be
00062        lost underneath the border.
00063 
00064      - in collapsing borders, because the borders collapse, we
00065        use the -continuous border- width to synthesize a border
00066        style and pass that in instead of using the element's
00067        assigned style directly.
00068 
00069        The continuous border on a given edge of an element is
00070        the collapse of all borders guaranteed to be continuous
00071        along that edge. Cell borders are ignored (because, for
00072        example, setting a thick border on the leftmost cell
00073        should not shift the row background over; this way a
00074        striped background set on <tr> will line up across rows
00075        even if the cells are assigned arbitrary border widths.
00076 
00077        For example, the continous border on the top edge of a
00078        row group is the collapse of any row group, row, and
00079        table borders involved. (The first row group's top would
00080        be [table-top + row group top + first row top]. It's bottom
00081        would be [row group bottom + last row bottom + next row
00082        top + next row group top].)
00083        The top edge of a column group likewise includes the
00084        table top, row group top, and first row top borders. However,
00085        it *also* includes its own top border, since that is guaranteed
00086        to be continuous. It does not include column borders because
00087        those are not guaranteed to be continuous: there may be two
00088        columns with different borders in a single column group.
00089 
00090        An alternative would be to define the continuous border as
00091          [table? + row group + row] for horizontal
00092          [table? + col group + col] for vertical
00093        This makes it easier to line up backgrounds across elements
00094        despite varying border widths, but it does not give much
00095        flexibility in aligning /to/ those border widths.
00096 */
00097 
00098 
00099 /* ~*~ TableBackgroundPainter ~*~
00100 
00101    The TableBackgroundPainter is created and destroyed in one painting call.
00102    Its principal function is PaintTable, which paints all table element
00103    backgrounds. The initial code in that method sets up an array of column
00104    data that caches the background styles and the border sizes for the
00105    columns and colgroups in TableBackgroundData structs in mCols. Data for
00106    BC borders are calculated and stashed in a synthesized border style struct
00107    in the data struct since collapsed borders aren't the same width as style-
00108    assigned borders. The data struct optimizes by only doing this if there's
00109    an image background; otherwise we don't care. //XXX should also check background-origin
00110    The class then loops through the row groups, rows, and cells. It uses
00111    the mRowGroup and mRow TableBackgroundData structs to cache data for
00112    the current frame in the loop. At the cell level, it paints the backgrounds,
00113    one over the other, inside the cell rect.
00114 
00115    The exception to this pattern is when a table element has a view.
00116    Elements with views are <dfn>passed through</dfn>, which means their data
00117    (and their descendants' data) are not cached. The full loop is still
00118    executed, however, so that underlying layers can get painted at the cell
00119    level.
00120 
00121    The TableBackgroundPainter is then destroyed.
00122 
00123    Elements with views set up their own painter to finish the painting
00124    process, since they were skipped. They call the appropriate sub-part
00125    of the loop (e.g. PaintRow) which will paint the frame and descendants.
00126  */
00127 
00128 TableBackgroundPainter::TableBackgroundData::TableBackgroundData()
00129   : mFrame(nsnull),
00130     mBackground(nsnull),
00131     mBorder(nsnull),
00132     mSynthBorder(nsnull)
00133 {
00134   MOZ_COUNT_CTOR(TableBackgroundData);
00135 }
00136 
00137 TableBackgroundPainter::TableBackgroundData::~TableBackgroundData()
00138 {
00139   NS_ASSERTION(!mSynthBorder, "must call Destroy before dtor");
00140   MOZ_COUNT_DTOR(TableBackgroundData);
00141 }
00142 
00143 void
00144 TableBackgroundPainter::TableBackgroundData::Destroy(nsPresContext* aPresContext)
00145 {
00146   NS_PRECONDITION(aPresContext, "null prescontext");
00147   if (mSynthBorder) {
00148     mSynthBorder->Destroy(aPresContext);
00149     mSynthBorder = nsnull;
00150   }
00151 }
00152 
00153 void
00154 TableBackgroundPainter::TableBackgroundData::Clear()
00155 {
00156   mRect.Empty();
00157   mFrame = nsnull;
00158   mBorder = nsnull;
00159   mBackground = nsnull;
00160 }
00161 
00162 void
00163 TableBackgroundPainter::TableBackgroundData::SetFrame(nsIFrame* aFrame)
00164 {
00165   NS_PRECONDITION(aFrame, "null frame");
00166   mFrame = aFrame;
00167   mRect = aFrame->GetRect();
00168 }
00169 
00170 void
00171 TableBackgroundPainter::TableBackgroundData::SetData(nsPresContext*      aPresContext,
00172                                                      nsIRenderingContext& aRenderingContext)
00173 {
00174   NS_PRECONDITION(mFrame, "null frame");
00175   /* IsVisibleForPainting doesn't use aRenderingContext except in nsTextFrames,
00176      so we're not going to bother translating.*/
00177   PRBool isVisible;
00178   nsresult rv = mFrame->IsVisibleForPainting(aPresContext, aRenderingContext,
00179                                              PR_TRUE, &isVisible);
00180   if (NS_SUCCEEDED(rv) && isVisible &&
00181       mFrame->GetStyleVisibility()->IsVisible()) {
00182     mBackground = mFrame->GetStyleBackground();
00183     mBorder = mFrame->GetStyleBorder();
00184   }
00185 }
00186 
00187 void
00188 TableBackgroundPainter::TableBackgroundData::SetFull(nsPresContext*      aPresContext,
00189                                                      nsIRenderingContext& aRenderingContext,
00190                                                      nsIFrame*            aFrame)
00191 {
00192   NS_PRECONDITION(aFrame, "null frame");
00193   SetFrame(aFrame);
00194   SetData(aPresContext, aRenderingContext);
00195 }
00196 
00197 inline PRBool
00198 TableBackgroundPainter::TableBackgroundData::ShouldSetBCBorder()
00199 {
00200   /* we only need accurate border data when positioning background images*/
00201   return mBackground && !(mBackground->mBackgroundFlags & NS_STYLE_BG_IMAGE_NONE);
00202 }
00203 
00204 nsresult
00205 TableBackgroundPainter::TableBackgroundData::SetBCBorder(nsMargin& aBorder,
00206                                                          TableBackgroundPainter* aPainter)
00207 {
00208   NS_PRECONDITION(aPainter, "null painter");
00209   if (!mSynthBorder) {
00210     mSynthBorder = new (aPainter->mPresContext)
00211                         nsStyleBorder(aPainter->mZeroBorder);
00212     if (!mSynthBorder) return NS_ERROR_OUT_OF_MEMORY;
00213   }
00214 
00215   NS_FOR_CSS_SIDES(side) {
00216     mSynthBorder->SetBorderWidth(side, aBorder.side(side));
00217   }
00218   
00219   mBorder = mSynthBorder;
00220   return NS_OK;
00221 }
00222 
00223 TableBackgroundPainter::TableBackgroundPainter(nsTableFrame*        aTableFrame,
00224                                                Origin               aOrigin,
00225                                                nsPresContext*      aPresContext,
00226                                                nsIRenderingContext& aRenderingContext,
00227                                                const nsRect&        aDirtyRect)
00228   : mPresContext(aPresContext),
00229     mRenderingContext(aRenderingContext),
00230     mDirtyRect(aDirtyRect),
00231     mOrigin(aOrigin),
00232     mCols(nsnull),
00233     mZeroBorder(aPresContext)
00234 {
00235   MOZ_COUNT_CTOR(TableBackgroundPainter);
00236 
00237   NS_FOR_CSS_SIDES(side) {
00238     mZeroBorder.SetBorderStyle(side, NS_STYLE_BORDER_STYLE_SOLID);
00239     mZeroBorder.SetBorderWidth(side, 0);
00240   }
00241 
00242   mZeroPadding.RecalcData();
00243 
00244   mP2t = mPresContext->ScaledPixelsToTwips();
00245   mIsBorderCollapse = aTableFrame->IsBorderCollapse();
00246 #ifdef DEBUG
00247   mCompatMode = mPresContext->CompatibilityMode();
00248 #endif
00249   mNumCols = aTableFrame->GetColCount();
00250 }
00251 
00252 TableBackgroundPainter::~TableBackgroundPainter()
00253 {
00254   if (mCols) {
00255     TableBackgroundData* lastColGroup = nsnull;
00256     for (PRUint32 i = 0; i < mNumCols; i++) {
00257       if (mCols[i].mColGroup != lastColGroup) {
00258         lastColGroup = mCols[i].mColGroup;
00259         NS_ASSERTION(mCols[i].mColGroup, "colgroup data should not be null - bug 237421");
00260         // we need to wallpaper a over zero pointer deref, bug 237421 will have the real fix
00261         if(lastColGroup)
00262           lastColGroup->Destroy(mPresContext);
00263         delete lastColGroup;
00264       }
00265       mCols[i].mColGroup = nsnull;
00266       mCols[i].mCol.Destroy(mPresContext);
00267     }
00268     delete [] mCols;
00269   }
00270   mRowGroup.Destroy(mPresContext);
00271   mRow.Destroy(mPresContext);
00272   MOZ_COUNT_DTOR(TableBackgroundPainter);
00273 }
00274 
00275 nsresult
00276 TableBackgroundPainter::PaintTableFrame(nsTableFrame*         aTableFrame,
00277                                         nsTableRowGroupFrame* aFirstRowGroup,
00278                                         nsTableRowGroupFrame* aLastRowGroup,
00279                                         nsMargin*             aDeflate)
00280 {
00281   NS_PRECONDITION(aTableFrame, "null frame");
00282   TableBackgroundData tableData;
00283   tableData.SetFull(mPresContext, mRenderingContext, aTableFrame);
00284   tableData.mRect.MoveTo(0,0); //using table's coords
00285   if (aDeflate) {
00286     tableData.mRect.Deflate(*aDeflate);
00287   }
00288   if (mIsBorderCollapse && tableData.ShouldSetBCBorder()) {
00289     if (aFirstRowGroup && aLastRowGroup && mNumCols > 0) {
00290       //only handle non-degenerate tables; we need a more robust BC model
00291       //to make degenerate tables' borders reasonable to deal with
00292       nsMargin border, tempBorder;
00293       nsTableColFrame* colFrame = aTableFrame->GetColFrame(mNumCols - 1);
00294       if (colFrame) {
00295         colFrame->GetContinuousBCBorderWidth(mP2t, tempBorder);
00296       }
00297       border.right = tempBorder.right;
00298 
00299       aLastRowGroup->GetContinuousBCBorderWidth(mP2t, tempBorder);
00300       border.bottom = tempBorder.bottom;
00301 
00302       nsTableRowFrame* rowFrame = aFirstRowGroup->GetFirstRow();
00303       if (rowFrame) {
00304         rowFrame->GetContinuousBCBorderWidth(mP2t, tempBorder);
00305         border.top = tempBorder.top;
00306       }
00307 
00308       border.left = aTableFrame->GetContinuousLeftBCBorderWidth(mP2t);
00309 
00310       nsresult rv = tableData.SetBCBorder(border, this);
00311       if (NS_FAILED(rv)) {
00312         tableData.Destroy(mPresContext);
00313         return rv;
00314       }
00315     }
00316   }
00317   if (tableData.IsVisible()) {
00318     nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
00319                                           tableData.mFrame, mDirtyRect,
00320                                           tableData.mRect,
00321                                           *tableData.mBackground,
00322                                           *tableData.mBorder,
00323                                           mZeroPadding, PR_TRUE);
00324   }
00325   tableData.Destroy(mPresContext);
00326   return NS_OK;
00327 }
00328 
00329 void
00330 TableBackgroundPainter::TranslateContext(nscoord aDX,
00331                                          nscoord aDY)
00332 {
00333   mRenderingContext.Translate(aDX, aDY);
00334   mDirtyRect.MoveBy(-aDX, -aDY);
00335   if (mCols) {
00336     TableBackgroundData* lastColGroup = nsnull;
00337     for (PRUint32 i = 0; i < mNumCols; i++) {
00338       mCols[i].mCol.mRect.MoveBy(-aDX, -aDY);
00339       if (lastColGroup != mCols[i].mColGroup) {
00340         NS_ASSERTION(mCols[i].mColGroup, "colgroup data should not be null - bug 237421");
00341         // we need to wallpaper a over zero pointer deref, bug 237421 will have the real fix
00342         if (!mCols[i].mColGroup)
00343           return;
00344         mCols[i].mColGroup->mRect.MoveBy(-aDX, -aDY);
00345         lastColGroup = mCols[i].mColGroup;
00346       }
00347     }
00348   }
00349 }
00350 
00351 nsresult
00352 TableBackgroundPainter::PaintTable(nsTableFrame* aTableFrame,
00353                                    nsMargin*     aDeflate)
00354 {
00355   NS_PRECONDITION(aTableFrame, "null table frame");
00356 
00357   nsVoidArray rowGroups;
00358   PRUint32 numRowGroups;
00359   aTableFrame->OrderRowGroups(rowGroups, numRowGroups);
00360 
00361   if (numRowGroups < 1) { //degenerate case
00362     PaintTableFrame(aTableFrame,nsnull, nsnull, nsnull);
00363     /* No cells; nothing else to paint */
00364     return NS_OK;
00365   }
00366 
00367   PaintTableFrame(aTableFrame,
00368                   aTableFrame->GetRowGroupFrame(NS_STATIC_CAST(nsIFrame*, rowGroups.ElementAt(0))),
00369                   aTableFrame->GetRowGroupFrame(NS_STATIC_CAST(nsIFrame*, rowGroups.ElementAt(numRowGroups - 1))),
00370                   aDeflate);
00371 
00372   /*Set up column background/border data*/
00373   if (mNumCols > 0) {
00374     nsFrameList& colGroupList = aTableFrame->GetColGroups();
00375     NS_ASSERTION(colGroupList.FirstChild(), "table should have at least one colgroup");
00376 
00377     mCols = new ColData[mNumCols];
00378     if (!mCols) return NS_ERROR_OUT_OF_MEMORY;
00379 
00380     TableBackgroundData* cgData = nsnull;
00381     nsMargin border;
00382     /* BC left borders aren't stored on cols, but the previous column's
00383        right border is the next one's left border.*/
00384     //Start with table's left border.
00385     nscoord lastLeftBorder = aTableFrame->GetContinuousLeftBCBorderWidth(mP2t);
00386     for (nsTableColGroupFrame* cgFrame = NS_STATIC_CAST(nsTableColGroupFrame*, colGroupList.FirstChild());
00387          cgFrame; cgFrame = NS_STATIC_CAST(nsTableColGroupFrame*, cgFrame->GetNextSibling())) {
00388 
00389       if (cgFrame->GetColCount() < 1) {
00390         //No columns, no cells, so no need for data
00391         continue;
00392       }
00393 
00394       /*Create data struct for column group*/
00395       cgData = new TableBackgroundData;
00396       if (!cgData) return NS_ERROR_OUT_OF_MEMORY;
00397       cgData->SetFull(mPresContext, mRenderingContext, cgFrame);
00398       if (mIsBorderCollapse && cgData->ShouldSetBCBorder()) {
00399         border.left = lastLeftBorder;
00400         cgFrame->GetContinuousBCBorderWidth(mP2t, border);
00401         nsresult rv = cgData->SetBCBorder(border, this);
00402         if (NS_FAILED(rv)) {
00403           cgData->Destroy(mPresContext);
00404           delete cgData;
00405           return rv;
00406         }
00407       }
00408 
00409       // Boolean that indicates whether mCols took ownership of cgData
00410       PRBool cgDataOwnershipTaken = PR_FALSE;
00411       
00412       /*Loop over columns in this colgroup*/
00413       if (cgData->IsVisible()) {
00414         for (nsTableColFrame* col = cgFrame->GetFirstColumn(); col;
00415              col = NS_STATIC_CAST(nsTableColFrame*, col->GetNextSibling())) {
00416           /*Create data struct for column*/
00417           PRUint32 colIndex = col->GetColIndex();
00418           NS_ASSERTION(colIndex < mNumCols, "prevent array boundary violation");
00419           if (mNumCols <= colIndex)
00420             break;
00421           mCols[colIndex].mCol.SetFull(mPresContext, mRenderingContext, col);
00422           //Bring column mRect into table's coord system
00423           mCols[colIndex].mCol.mRect.MoveBy(cgData->mRect.x, cgData->mRect.y);
00424           //link to parent colgroup's data
00425           mCols[colIndex].mColGroup = cgData;
00426           cgDataOwnershipTaken = PR_TRUE;
00427           if (mIsBorderCollapse) {
00428             border.left = lastLeftBorder;
00429             lastLeftBorder = col->GetContinuousBCBorderWidth(mP2t, border);
00430             if (mCols[colIndex].mCol.ShouldSetBCBorder()) {
00431               nsresult rv = mCols[colIndex].mCol.SetBCBorder(border, this);
00432               if (NS_FAILED(rv)) return rv;
00433             }
00434           }
00435         }
00436       }
00437 
00438       if (!cgDataOwnershipTaken) {
00439         cgData->Destroy(mPresContext);
00440         delete cgData;
00441       }
00442     }
00443   }
00444 
00445   for (PRUint32 i = 0; i < numRowGroups; i++) {
00446     nsTableRowGroupFrame* rg = nsTableFrame::GetRowGroupFrame(NS_STATIC_CAST(nsIFrame*, rowGroups.ElementAt(i)));
00447     mRowGroup.SetFrame(rg);
00448     // Need to compute the right rect via GetOffsetTo, since the row
00449     // group may not be a child of the table.
00450     mRowGroup.mRect.MoveTo(rg->GetOffsetTo(aTableFrame));
00451     if (mRowGroup.mRect.Intersects(mDirtyRect)) {
00452       nsresult rv = PaintRowGroup(rg, rg->HasView());
00453       if (NS_FAILED(rv)) return rv;
00454     }
00455   }
00456   return NS_OK;
00457 }
00458 
00459 nsresult
00460 TableBackgroundPainter::PaintRowGroup(nsTableRowGroupFrame* aFrame,
00461                                       PRBool                aPassThrough)
00462 {
00463   NS_PRECONDITION(aFrame, "null frame");
00464 
00465   if (!mRowGroup.mFrame) {
00466     mRowGroup.SetFrame(aFrame);
00467   }
00468 
00469   nsTableRowFrame* firstRow = aFrame->GetFirstRow();
00470 
00471   /* Load row group data */
00472   if (!aPassThrough) {
00473     mRowGroup.SetData(mPresContext, mRenderingContext);
00474     if (mIsBorderCollapse && mRowGroup.ShouldSetBCBorder()) {
00475       nsMargin border;
00476       if (firstRow) {
00477         //pick up first row's top border (= rg top border)
00478         firstRow->GetContinuousBCBorderWidth(mP2t, border);
00479         /* (row group doesn't store its top border) */
00480       }
00481       //overwrite sides+bottom borders with rg's own
00482       aFrame->GetContinuousBCBorderWidth(mP2t, border);
00483       nsresult res = mRowGroup.SetBCBorder(border, this);
00484       if (!NS_SUCCEEDED(res)) {
00485         return res;
00486       }
00487     }
00488     aPassThrough = !mRowGroup.IsVisible();
00489   }
00490 
00491   /* translate everything into row group coord system*/
00492   if (eOrigin_TableRowGroup != mOrigin) {
00493     TranslateContext(mRowGroup.mRect.x, mRowGroup.mRect.y);
00494   }
00495   nsRect rgRect = mRowGroup.mRect;
00496   mRowGroup.mRect.MoveTo(0, 0);
00497 
00498   /* paint */
00499   for (nsTableRowFrame* row = firstRow; row; row = row->GetNextRow()) {
00500     mRow.SetFrame(row);
00501     if (mDirtyRect.YMost() >= mRow.mRect.y) { //Intersect wouldn't handle rowspans
00502       nsresult rv = PaintRow(row, aPassThrough || row->HasView());
00503       if (NS_FAILED(rv)) return rv;
00504     }
00505   }
00506 
00507   /* translate back into table coord system */
00508   if (eOrigin_TableRowGroup != mOrigin) {
00509     TranslateContext(-rgRect.x, -rgRect.y);
00510   }
00511   
00512   /* unload rg data */
00513   mRowGroup.Clear();
00514 
00515   return NS_OK;
00516 }
00517 
00518 nsresult
00519 TableBackgroundPainter::PaintRow(nsTableRowFrame* aFrame,
00520                                  PRBool           aPassThrough)
00521 {
00522   NS_PRECONDITION(aFrame, "null frame");
00523 
00524   if (!mRow.mFrame) {
00525     mRow.SetFrame(aFrame);
00526   }
00527 
00528   /* Load row data */
00529   if (!aPassThrough) {
00530     mRow.SetData(mPresContext, mRenderingContext);
00531     if (mIsBorderCollapse && mRow.ShouldSetBCBorder()) {
00532       nsMargin border;
00533       nsTableRowFrame* nextRow = aFrame->GetNextRow();
00534       if (nextRow) { //outer top below us is inner bottom for us
00535         border.bottom = nextRow->GetOuterTopContBCBorderWidth(mP2t);
00536       }
00537       else { //acquire rg's bottom border
00538         nsTableRowGroupFrame* rowGroup = NS_STATIC_CAST(nsTableRowGroupFrame*, aFrame->GetParent());
00539         rowGroup->GetContinuousBCBorderWidth(mP2t, border);
00540       }
00541       //get the rest of the borders; will overwrite all but bottom
00542       aFrame->GetContinuousBCBorderWidth(mP2t, border);
00543 
00544       nsresult res = mRow.SetBCBorder(border, this);
00545       if (!NS_SUCCEEDED(res)) {
00546         return res;
00547       }
00548     }
00549     aPassThrough = !mRow.IsVisible();
00550   }
00551 
00552   /* Translate */
00553   if (eOrigin_TableRow == mOrigin) {
00554     /* If we originate from the row, then make the row the origin. */
00555     mRow.mRect.MoveTo(0, 0);
00556   }
00557   //else: Use row group's coord system -> no translation necessary
00558 
00559   for (nsTableCellFrame* cell = aFrame->GetFirstCell(); cell; cell = cell->GetNextCell()) {
00560     mCellRect = cell->GetRect();
00561     //Translate to use the same coord system as mRow.
00562     mCellRect.MoveBy(mRow.mRect.x, mRow.mRect.y);
00563     if (mCellRect.Intersects(mDirtyRect)) {
00564       nsresult rv = PaintCell(cell, aPassThrough || cell->HasView());
00565       if (NS_FAILED(rv)) return rv;
00566     }
00567   }
00568 
00569   /* Unload row data */
00570   mRow.Clear();
00571   return NS_OK;
00572 }
00573 
00574 nsresult
00575 TableBackgroundPainter::PaintCell(nsTableCellFrame* aCell,
00576                                   PRBool aPassSelf)
00577 {
00578   NS_PRECONDITION(aCell, "null frame");
00579 
00580   const nsStyleTableBorder* cellTableStyle;
00581   cellTableStyle = aCell->GetStyleTableBorder();
00582   if (!(NS_STYLE_TABLE_EMPTY_CELLS_SHOW == cellTableStyle->mEmptyCells ||
00583         NS_STYLE_TABLE_EMPTY_CELLS_SHOW_BACKGROUND == cellTableStyle->mEmptyCells)
00584       && aCell->GetContentEmpty()) {
00585     return NS_OK;
00586   }
00587 
00588   PRInt32 colIndex;
00589   aCell->GetColIndex(colIndex);
00590   NS_ASSERTION(colIndex < mNumCols, "prevent array boundary violation");
00591   if (mNumCols <= colIndex)
00592     return NS_OK;
00593 
00594   //Paint column group background
00595   if (mCols && mCols[colIndex].mColGroup && mCols[colIndex].mColGroup->IsVisible()) {
00596     nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
00597                                           mCols[colIndex].mColGroup->mFrame, mDirtyRect,
00598                                           mCols[colIndex].mColGroup->mRect,
00599                                           *mCols[colIndex].mColGroup->mBackground,
00600                                           *mCols[colIndex].mColGroup->mBorder,
00601                                           mZeroPadding, PR_TRUE, &mCellRect);
00602   }
00603 
00604   //Paint column background
00605   if (mCols && mCols[colIndex].mCol.IsVisible()) {
00606     nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
00607                                           mCols[colIndex].mCol.mFrame, mDirtyRect,
00608                                           mCols[colIndex].mCol.mRect,
00609                                           *mCols[colIndex].mCol.mBackground,
00610                                           *mCols[colIndex].mCol.mBorder,
00611                                           mZeroPadding, PR_TRUE, &mCellRect);
00612   }
00613 
00614   //Paint row group background
00615   if (mRowGroup.IsVisible()) {
00616     nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
00617                                           mRowGroup.mFrame, mDirtyRect, mRowGroup.mRect,
00618                                           *mRowGroup.mBackground, *mRowGroup.mBorder,
00619                                           mZeroPadding, PR_TRUE, &mCellRect);
00620   }
00621 
00622   //Paint row background
00623   if (mRow.IsVisible()) {
00624     nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
00625                                           mRow.mFrame, mDirtyRect, mRow.mRect,
00626                                           *mRow.mBackground, *mRow.mBorder,
00627                                           mZeroPadding, PR_TRUE, &mCellRect);
00628   }
00629 
00630   //Paint cell background in border-collapse unless we're just passing
00631   if (mIsBorderCollapse && !aPassSelf) {
00632     mRenderingContext.PushState();
00633     mRenderingContext.Translate(mCellRect.x, mCellRect.y);
00634     mDirtyRect.MoveBy(-mCellRect.x, -mCellRect.y);
00635     aCell->Paint(mPresContext, mRenderingContext, mDirtyRect,
00636                  NS_FRAME_PAINT_LAYER_BACKGROUND,
00637                  NS_PAINT_FLAG_TABLE_BG_PAINT | NS_PAINT_FLAG_TABLE_CELL_BG_PASS);
00638     mDirtyRect.MoveBy(mCellRect.x, mCellRect.y);
00639     mRenderingContext.PopState();
00640   }
00641 
00642   return NS_OK;
00643 }