michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0:
michael@0: #include "nsTableFrame.h"
michael@0: #include "nsTableRowGroupFrame.h"
michael@0: #include "nsTableRowFrame.h"
michael@0: #include "nsTableColGroupFrame.h"
michael@0: #include "nsTableColFrame.h"
michael@0: #include "nsTableCellFrame.h"
michael@0: #include "nsTablePainter.h"
michael@0: #include "nsCSSRendering.h"
michael@0: #include "nsDisplayList.h"
michael@0:
michael@0: /* ~*~ Table Background Painting ~*~
michael@0:
michael@0: Mozilla's Table Background painting follows CSS2.1:17.5.1
michael@0: That section does not, however, describe the effect of
michael@0: borders on background image positioning. What we do is:
michael@0:
michael@0: - in separate borders, the borders are passed in so that
michael@0: their width figures in image positioning, even for rows/cols, which
michael@0: don't have visible borders. This is done to allow authors
michael@0: to position row backgrounds by, for example, aligning the
michael@0: top left corner with the top left padding corner of the
michael@0: top left table cell in the row in cases where all cells
michael@0: have consistent border widths. If we didn't honor these
michael@0: invisible borders, there would be no way to align
michael@0: backgrounds with the padding edges, and designs would be
michael@0: lost underneath the border.
michael@0:
michael@0: - in collapsing borders, because the borders collapse, we
michael@0: use the -continuous border- width to synthesize a border
michael@0: style and pass that in instead of using the element's
michael@0: assigned style directly.
michael@0:
michael@0: The continuous border on a given edge of an element is
michael@0: the collapse of all borders guaranteed to be continuous
michael@0: along that edge. Cell borders are ignored (because, for
michael@0: example, setting a thick border on the leftmost cell
michael@0: should not shift the row background over; this way a
michael@0: striped background set on
will line up across rows
michael@0: even if the cells are assigned arbitrary border widths.
michael@0:
michael@0: For example, the continuous border on the top edge of a
michael@0: row group is the collapse of any row group, row, and
michael@0: table borders involved. (The first row group's top would
michael@0: be [table-top + row group top + first row top]. It's bottom
michael@0: would be [row group bottom + last row bottom + next row
michael@0: top + next row group top].)
michael@0: The top edge of a column group likewise includes the
michael@0: table top, row group top, and first row top borders. However,
michael@0: it *also* includes its own top border, since that is guaranteed
michael@0: to be continuous. It does not include column borders because
michael@0: those are not guaranteed to be continuous: there may be two
michael@0: columns with different borders in a single column group.
michael@0:
michael@0: An alternative would be to define the continuous border as
michael@0: [table? + row group + row] for horizontal
michael@0: [table? + col group + col] for vertical
michael@0: This makes it easier to line up backgrounds across elements
michael@0: despite varying border widths, but it does not give much
michael@0: flexibility in aligning /to/ those border widths.
michael@0: */
michael@0:
michael@0:
michael@0: /* ~*~ TableBackgroundPainter ~*~
michael@0:
michael@0: The TableBackgroundPainter is created and destroyed in one painting call.
michael@0: Its principal function is PaintTable, which paints all table element
michael@0: backgrounds. The initial code in that method sets up an array of column
michael@0: data that caches the background styles and the border sizes for the
michael@0: columns and colgroups in TableBackgroundData structs in mCols. Data for
michael@0: BC borders are calculated and stashed in a synthesized border style struct
michael@0: in the data struct since collapsed borders aren't the same width as style-
michael@0: assigned borders. The data struct optimizes by only doing this if there's
michael@0: an image background; otherwise we don't care. //XXX should also check background-origin
michael@0: The class then loops through the row groups, rows, and cells. It uses
michael@0: the mRowGroup and mRow TableBackgroundData structs to cache data for
michael@0: the current frame in the loop. At the cell level, it paints the backgrounds,
michael@0: one over the other, inside the cell rect.
michael@0:
michael@0: The exception to this pattern is when a table element creates a (pseudo)
michael@0: stacking context. Elements with stacking contexts (e.g., 'opacity' applied)
michael@0: are passed through, which means their data (and their
michael@0: descendants' data) are not cached. The full loop is still executed, however,
michael@0: so that underlying layers can get painted at the cell level.
michael@0:
michael@0: The TableBackgroundPainter is then destroyed.
michael@0:
michael@0: Elements with stacking contexts set up their own painter to finish the
michael@0: painting process, since they were skipped. They call the appropriate
michael@0: sub-part of the loop (e.g. PaintRow) which will paint the frame and
michael@0: descendants. Note that it is permissible according to CSS2.1 to ignore'
michael@0: 'position:relative' (and implicitly, 'opacity') on table parts so that
michael@0: table parts can never create stacking contexts; if we want to, we can
michael@0: implement that, and then we won't have to deal with TableBackgroundPainter
michael@0: being used anywhere but from the nsTableFrame.
michael@0:
michael@0: XXX views are going
michael@0: */
michael@0:
michael@0: TableBackgroundPainter::TableBackgroundData::TableBackgroundData()
michael@0: : mFrame(nullptr),
michael@0: mVisible(false),
michael@0: mBorder(nullptr),
michael@0: mSynthBorder(nullptr)
michael@0: {
michael@0: MOZ_COUNT_CTOR(TableBackgroundData);
michael@0: }
michael@0:
michael@0: TableBackgroundPainter::TableBackgroundData::~TableBackgroundData()
michael@0: {
michael@0: NS_ASSERTION(!mSynthBorder, "must call Destroy before dtor");
michael@0: MOZ_COUNT_DTOR(TableBackgroundData);
michael@0: }
michael@0:
michael@0: void
michael@0: TableBackgroundPainter::TableBackgroundData::Destroy(nsPresContext* aPresContext)
michael@0: {
michael@0: NS_PRECONDITION(aPresContext, "null prescontext");
michael@0: if (mSynthBorder) {
michael@0: mSynthBorder->Destroy(aPresContext);
michael@0: mSynthBorder = nullptr;
michael@0: }
michael@0: }
michael@0:
michael@0: void
michael@0: TableBackgroundPainter::TableBackgroundData::Clear()
michael@0: {
michael@0: mRect.SetEmpty();
michael@0: mFrame = nullptr;
michael@0: mBorder = nullptr;
michael@0: mVisible = false;
michael@0: }
michael@0:
michael@0: void
michael@0: TableBackgroundPainter::TableBackgroundData::SetFrame(nsIFrame* aFrame)
michael@0: {
michael@0: NS_PRECONDITION(aFrame, "null frame");
michael@0: mFrame = aFrame;
michael@0: mRect = aFrame->GetRect();
michael@0: }
michael@0:
michael@0: void
michael@0: TableBackgroundPainter::TableBackgroundData::SetData()
michael@0: {
michael@0: NS_PRECONDITION(mFrame, "null frame");
michael@0: if (mFrame->IsVisibleForPainting()) {
michael@0: mVisible = true;
michael@0: mBorder = mFrame->StyleBorder();
michael@0: }
michael@0: }
michael@0:
michael@0: void
michael@0: TableBackgroundPainter::TableBackgroundData::SetFull(nsIFrame* aFrame)
michael@0: {
michael@0: NS_PRECONDITION(aFrame, "null frame");
michael@0: SetFrame(aFrame);
michael@0: SetData();
michael@0: }
michael@0:
michael@0: inline bool
michael@0: TableBackgroundPainter::TableBackgroundData::ShouldSetBCBorder()
michael@0: {
michael@0: /* we only need accurate border data when positioning background images*/
michael@0: if (!mVisible) {
michael@0: return false;
michael@0: }
michael@0:
michael@0: const nsStyleBackground *bg = mFrame->StyleBackground();
michael@0: NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) {
michael@0: if (!bg->mLayers[i].mImage.IsEmpty())
michael@0: return true;
michael@0: }
michael@0: return false;
michael@0: }
michael@0:
michael@0: nsresult
michael@0: TableBackgroundPainter::TableBackgroundData::SetBCBorder(nsMargin& aBorder,
michael@0: TableBackgroundPainter* aPainter)
michael@0: {
michael@0: NS_PRECONDITION(aPainter, "null painter");
michael@0: if (!mSynthBorder) {
michael@0: mSynthBorder = new (aPainter->mPresContext)
michael@0: nsStyleBorder(aPainter->mZeroBorder);
michael@0: if (!mSynthBorder) return NS_ERROR_OUT_OF_MEMORY;
michael@0: }
michael@0:
michael@0: NS_FOR_CSS_SIDES(side) {
michael@0: mSynthBorder->SetBorderWidth(side, aBorder.Side(side));
michael@0: }
michael@0:
michael@0: mBorder = mSynthBorder;
michael@0: return NS_OK;
michael@0: }
michael@0:
michael@0: TableBackgroundPainter::TableBackgroundPainter(nsTableFrame* aTableFrame,
michael@0: Origin aOrigin,
michael@0: nsPresContext* aPresContext,
michael@0: nsRenderingContext& aRenderingContext,
michael@0: const nsRect& aDirtyRect,
michael@0: const nsPoint& aRenderPt,
michael@0: uint32_t aBGPaintFlags)
michael@0: : mPresContext(aPresContext),
michael@0: mRenderingContext(aRenderingContext),
michael@0: mRenderPt(aRenderPt),
michael@0: mDirtyRect(aDirtyRect),
michael@0: mOrigin(aOrigin),
michael@0: mCols(nullptr),
michael@0: mZeroBorder(aPresContext),
michael@0: mBGPaintFlags(aBGPaintFlags)
michael@0: {
michael@0: MOZ_COUNT_CTOR(TableBackgroundPainter);
michael@0:
michael@0: NS_FOR_CSS_SIDES(side) {
michael@0: mZeroBorder.SetBorderStyle(side, NS_STYLE_BORDER_STYLE_SOLID);
michael@0: mZeroBorder.SetBorderWidth(side, 0);
michael@0: }
michael@0:
michael@0: mIsBorderCollapse = aTableFrame->IsBorderCollapse();
michael@0: #ifdef DEBUG
michael@0: mCompatMode = mPresContext->CompatibilityMode();
michael@0: #endif
michael@0: mNumCols = aTableFrame->GetColCount();
michael@0: }
michael@0:
michael@0: TableBackgroundPainter::~TableBackgroundPainter()
michael@0: {
michael@0: if (mCols) {
michael@0: TableBackgroundData* lastColGroup = nullptr;
michael@0: for (uint32_t i = 0; i < mNumCols; i++) {
michael@0: if (mCols[i].mColGroup != lastColGroup) {
michael@0: lastColGroup = mCols[i].mColGroup;
michael@0: NS_ASSERTION(mCols[i].mColGroup, "colgroup data should not be null - bug 237421");
michael@0: // we need to wallpaper a over zero pointer deref, bug 237421 will have the real fix
michael@0: if(lastColGroup)
michael@0: lastColGroup->Destroy(mPresContext);
michael@0: delete lastColGroup;
michael@0: }
michael@0: mCols[i].mColGroup = nullptr;
michael@0: mCols[i].mCol.Destroy(mPresContext);
michael@0: }
michael@0: delete [] mCols;
michael@0: }
michael@0: mRowGroup.Destroy(mPresContext);
michael@0: mRow.Destroy(mPresContext);
michael@0: MOZ_COUNT_DTOR(TableBackgroundPainter);
michael@0: }
michael@0:
michael@0: nsresult
michael@0: TableBackgroundPainter::PaintTableFrame(nsTableFrame* aTableFrame,
michael@0: nsTableRowGroupFrame* aFirstRowGroup,
michael@0: nsTableRowGroupFrame* aLastRowGroup,
michael@0: const nsMargin& aDeflate)
michael@0: {
michael@0: NS_PRECONDITION(aTableFrame, "null frame");
michael@0: TableBackgroundData tableData;
michael@0: tableData.SetFull(aTableFrame);
michael@0: tableData.mRect.MoveTo(0,0); //using table's coords
michael@0: tableData.mRect.Deflate(aDeflate);
michael@0: if (mIsBorderCollapse && tableData.ShouldSetBCBorder()) {
michael@0: if (aFirstRowGroup && aLastRowGroup && mNumCols > 0) {
michael@0: //only handle non-degenerate tables; we need a more robust BC model
michael@0: //to make degenerate tables' borders reasonable to deal with
michael@0: nsMargin border, tempBorder;
michael@0: nsTableColFrame* colFrame = aTableFrame->GetColFrame(mNumCols - 1);
michael@0: if (colFrame) {
michael@0: colFrame->GetContinuousBCBorderWidth(tempBorder);
michael@0: }
michael@0: border.right = tempBorder.right;
michael@0:
michael@0: aLastRowGroup->GetContinuousBCBorderWidth(tempBorder);
michael@0: border.bottom = tempBorder.bottom;
michael@0:
michael@0: nsTableRowFrame* rowFrame = aFirstRowGroup->GetFirstRow();
michael@0: if (rowFrame) {
michael@0: rowFrame->GetContinuousBCBorderWidth(tempBorder);
michael@0: border.top = tempBorder.top;
michael@0: }
michael@0:
michael@0: border.left = aTableFrame->GetContinuousLeftBCBorderWidth();
michael@0:
michael@0: nsresult rv = tableData.SetBCBorder(border, this);
michael@0: if (NS_FAILED(rv)) {
michael@0: tableData.Destroy(mPresContext);
michael@0: return rv;
michael@0: }
michael@0: }
michael@0: }
michael@0: if (tableData.IsVisible()) {
michael@0: nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
michael@0: tableData.mFrame, mDirtyRect,
michael@0: tableData.mRect + mRenderPt,
michael@0: tableData.mFrame->StyleContext(),
michael@0: *tableData.mBorder,
michael@0: mBGPaintFlags);
michael@0: }
michael@0: tableData.Destroy(mPresContext);
michael@0: return NS_OK;
michael@0: }
michael@0:
michael@0: void
michael@0: TableBackgroundPainter::TranslateContext(nscoord aDX,
michael@0: nscoord aDY)
michael@0: {
michael@0: mRenderPt += nsPoint(aDX, aDY);
michael@0: if (mCols) {
michael@0: TableBackgroundData* lastColGroup = nullptr;
michael@0: for (uint32_t i = 0; i < mNumCols; i++) {
michael@0: mCols[i].mCol.mRect.MoveBy(-aDX, -aDY);
michael@0: if (lastColGroup != mCols[i].mColGroup) {
michael@0: NS_ASSERTION(mCols[i].mColGroup, "colgroup data should not be null - bug 237421");
michael@0: // we need to wallpaper a over zero pointer deref, bug 237421 will have the real fix
michael@0: if (!mCols[i].mColGroup)
michael@0: return;
michael@0: mCols[i].mColGroup->mRect.MoveBy(-aDX, -aDY);
michael@0: lastColGroup = mCols[i].mColGroup;
michael@0: }
michael@0: }
michael@0: }
michael@0: }
michael@0:
michael@0: nsresult
michael@0: TableBackgroundPainter::PaintTable(nsTableFrame* aTableFrame,
michael@0: const nsMargin& aDeflate,
michael@0: bool aPaintTableBackground)
michael@0: {
michael@0: NS_PRECONDITION(aTableFrame, "null table frame");
michael@0:
michael@0: nsTableFrame::RowGroupArray rowGroups;
michael@0: aTableFrame->OrderRowGroups(rowGroups);
michael@0:
michael@0: if (rowGroups.Length() < 1) { //degenerate case
michael@0: if (aPaintTableBackground) {
michael@0: PaintTableFrame(aTableFrame, nullptr, nullptr, nsMargin(0,0,0,0));
michael@0: }
michael@0: /* No cells; nothing else to paint */
michael@0: return NS_OK;
michael@0: }
michael@0:
michael@0: if (aPaintTableBackground) {
michael@0: PaintTableFrame(aTableFrame, rowGroups[0], rowGroups[rowGroups.Length() - 1],
michael@0: aDeflate);
michael@0: }
michael@0:
michael@0: /*Set up column background/border data*/
michael@0: if (mNumCols > 0) {
michael@0: nsFrameList& colGroupList = aTableFrame->GetColGroups();
michael@0: NS_ASSERTION(colGroupList.FirstChild(), "table should have at least one colgroup");
michael@0:
michael@0: mCols = new ColData[mNumCols];
michael@0: if (!mCols) return NS_ERROR_OUT_OF_MEMORY;
michael@0:
michael@0: TableBackgroundData* cgData = nullptr;
michael@0: nsMargin border;
michael@0: /* BC left borders aren't stored on cols, but the previous column's
michael@0: right border is the next one's left border.*/
michael@0: //Start with table's left border.
michael@0: nscoord lastLeftBorder = aTableFrame->GetContinuousLeftBCBorderWidth();
michael@0: for (nsTableColGroupFrame* cgFrame = static_cast(colGroupList.FirstChild());
michael@0: cgFrame; cgFrame = static_cast(cgFrame->GetNextSibling())) {
michael@0:
michael@0: if (cgFrame->GetColCount() < 1) {
michael@0: //No columns, no cells, so no need for data
michael@0: continue;
michael@0: }
michael@0:
michael@0: /*Create data struct for column group*/
michael@0: cgData = new TableBackgroundData;
michael@0: if (!cgData) return NS_ERROR_OUT_OF_MEMORY;
michael@0: cgData->SetFull(cgFrame);
michael@0: if (mIsBorderCollapse && cgData->ShouldSetBCBorder()) {
michael@0: border.left = lastLeftBorder;
michael@0: cgFrame->GetContinuousBCBorderWidth(border);
michael@0: nsresult rv = cgData->SetBCBorder(border, this);
michael@0: if (NS_FAILED(rv)) {
michael@0: cgData->Destroy(mPresContext);
michael@0: delete cgData;
michael@0: return rv;
michael@0: }
michael@0: }
michael@0:
michael@0: // Boolean that indicates whether mCols took ownership of cgData
michael@0: bool cgDataOwnershipTaken = false;
michael@0:
michael@0: /*Loop over columns in this colgroup*/
michael@0: for (nsTableColFrame* col = cgFrame->GetFirstColumn(); col;
michael@0: col = static_cast(col->GetNextSibling())) {
michael@0: /*Create data struct for column*/
michael@0: uint32_t colIndex = col->GetColIndex();
michael@0: NS_ASSERTION(colIndex < mNumCols, "prevent array boundary violation");
michael@0: if (mNumCols <= colIndex)
michael@0: break;
michael@0: mCols[colIndex].mCol.SetFull(col);
michael@0: //Bring column mRect into table's coord system
michael@0: mCols[colIndex].mCol.mRect.MoveBy(cgData->mRect.x, cgData->mRect.y);
michael@0: //link to parent colgroup's data
michael@0: mCols[colIndex].mColGroup = cgData;
michael@0: cgDataOwnershipTaken = true;
michael@0: if (mIsBorderCollapse) {
michael@0: border.left = lastLeftBorder;
michael@0: lastLeftBorder = col->GetContinuousBCBorderWidth(border);
michael@0: if (mCols[colIndex].mCol.ShouldSetBCBorder()) {
michael@0: nsresult rv = mCols[colIndex].mCol.SetBCBorder(border, this);
michael@0: if (NS_FAILED(rv)) return rv;
michael@0: }
michael@0: }
michael@0: }
michael@0:
michael@0: if (!cgDataOwnershipTaken) {
michael@0: cgData->Destroy(mPresContext);
michael@0: delete cgData;
michael@0: }
michael@0: }
michael@0: }
michael@0:
michael@0: for (uint32_t i = 0; i < rowGroups.Length(); i++) {
michael@0: nsTableRowGroupFrame* rg = rowGroups[i];
michael@0: mRowGroup.SetFrame(rg);
michael@0: // Need to compute the right rect via GetOffsetTo, since the row
michael@0: // group may not be a child of the table.
michael@0: mRowGroup.mRect.MoveTo(rg->GetOffsetTo(aTableFrame));
michael@0: if (mRowGroup.mRect.Intersects(mDirtyRect - mRenderPt)) {
michael@0: nsresult rv = PaintRowGroup(rg, rg->IsPseudoStackingContextFromStyle());
michael@0: if (NS_FAILED(rv)) return rv;
michael@0: }
michael@0: }
michael@0: return NS_OK;
michael@0: }
michael@0:
michael@0: nsresult
michael@0: TableBackgroundPainter::PaintRowGroup(nsTableRowGroupFrame* aFrame,
michael@0: bool aPassThrough)
michael@0: {
michael@0: NS_PRECONDITION(aFrame, "null frame");
michael@0:
michael@0: if (!mRowGroup.mFrame) {
michael@0: mRowGroup.SetFrame(aFrame);
michael@0: }
michael@0:
michael@0: nsTableRowFrame* firstRow = aFrame->GetFirstRow();
michael@0:
michael@0: /* Load row group data */
michael@0: if (!aPassThrough) {
michael@0: mRowGroup.SetData();
michael@0: if (mIsBorderCollapse && mRowGroup.ShouldSetBCBorder()) {
michael@0: nsMargin border;
michael@0: if (firstRow) {
michael@0: //pick up first row's top border (= rg top border)
michael@0: firstRow->GetContinuousBCBorderWidth(border);
michael@0: /* (row group doesn't store its top border) */
michael@0: }
michael@0: //overwrite sides+bottom borders with rg's own
michael@0: aFrame->GetContinuousBCBorderWidth(border);
michael@0: nsresult res = mRowGroup.SetBCBorder(border, this);
michael@0: if (!NS_SUCCEEDED(res)) {
michael@0: return res;
michael@0: }
michael@0: }
michael@0: aPassThrough = !mRowGroup.IsVisible();
michael@0: }
michael@0:
michael@0: /* translate everything into row group coord system*/
michael@0: if (eOrigin_TableRowGroup != mOrigin) {
michael@0: TranslateContext(mRowGroup.mRect.x, mRowGroup.mRect.y);
michael@0: }
michael@0: nsRect rgRect = mRowGroup.mRect;
michael@0: mRowGroup.mRect.MoveTo(0, 0);
michael@0:
michael@0: /* Find the right row to start with */
michael@0: nscoord ignored; // We don't care about overflow above, since what we really
michael@0: // care about are backgrounds and overflow above doesn't
michael@0: // correspond to backgrounds, since cells can't span up from
michael@0: // their originating row. We do care about overflow below,
michael@0: // however, since that can be due to rowspans.
michael@0:
michael@0: // Note that mDirtyRect - mRenderPt is guaranteed to be in the row
michael@0: // group's coordinate system here, so passing its .y to
michael@0: // GetFirstRowContaining is ok.
michael@0: nsIFrame* cursor = aFrame->GetFirstRowContaining(mDirtyRect.y - mRenderPt.y, &ignored);
michael@0:
michael@0: // Sadly, it seems like there may be non-row frames in there... or something?
michael@0: // There are certainly null-checks in GetFirstRow() and GetNextRow(). :(
michael@0: while (cursor && cursor->GetType() != nsGkAtoms::tableRowFrame) {
michael@0: cursor = cursor->GetNextSibling();
michael@0: }
michael@0:
michael@0: // It's OK if cursor is null here.
michael@0: nsTableRowFrame* row = static_cast(cursor);
michael@0: if (!row) {
michael@0: // No useful cursor; just start at the top. Don't bother to set up a
michael@0: // cursor; if we've gotten this far then we've already built the display
michael@0: // list for the rowgroup, so not having a cursor means that there's some
michael@0: // good reason we don't have a cursor and we shouldn't create one here.
michael@0: row = firstRow;
michael@0: }
michael@0:
michael@0: /* Finally paint */
michael@0: for (; row; row = row->GetNextRow()) {
michael@0: mRow.SetFrame(row);
michael@0: if (mDirtyRect.YMost() - mRenderPt.y < mRow.mRect.y) { // Intersect wouldn't handle
michael@0: // rowspans.
michael@0:
michael@0: // All done; cells originating in later rows can't intersect mDirtyRect.
michael@0: break;
michael@0: }
michael@0:
michael@0: nsresult rv = PaintRow(row, aPassThrough || row->IsPseudoStackingContextFromStyle());
michael@0: if (NS_FAILED(rv)) return rv;
michael@0: }
michael@0:
michael@0: /* translate back into table coord system */
michael@0: if (eOrigin_TableRowGroup != mOrigin) {
michael@0: TranslateContext(-rgRect.x, -rgRect.y);
michael@0: }
michael@0:
michael@0: /* unload rg data */
michael@0: mRowGroup.Clear();
michael@0:
michael@0: return NS_OK;
michael@0: }
michael@0:
michael@0: nsresult
michael@0: TableBackgroundPainter::PaintRow(nsTableRowFrame* aFrame,
michael@0: bool aPassThrough)
michael@0: {
michael@0: NS_PRECONDITION(aFrame, "null frame");
michael@0:
michael@0: if (!mRow.mFrame) {
michael@0: mRow.SetFrame(aFrame);
michael@0: }
michael@0:
michael@0: /* Load row data */
michael@0: if (!aPassThrough) {
michael@0: mRow.SetData();
michael@0: if (mIsBorderCollapse && mRow.ShouldSetBCBorder()) {
michael@0: nsMargin border;
michael@0: nsTableRowFrame* nextRow = aFrame->GetNextRow();
michael@0: if (nextRow) { //outer top below us is inner bottom for us
michael@0: border.bottom = nextRow->GetOuterTopContBCBorderWidth();
michael@0: }
michael@0: else { //acquire rg's bottom border
michael@0: nsTableRowGroupFrame* rowGroup = static_cast(aFrame->GetParent());
michael@0: rowGroup->GetContinuousBCBorderWidth(border);
michael@0: }
michael@0: //get the rest of the borders; will overwrite all but bottom
michael@0: aFrame->GetContinuousBCBorderWidth(border);
michael@0:
michael@0: nsresult res = mRow.SetBCBorder(border, this);
michael@0: if (!NS_SUCCEEDED(res)) {
michael@0: return res;
michael@0: }
michael@0: }
michael@0: aPassThrough = !mRow.IsVisible();
michael@0: }
michael@0:
michael@0: /* Translate */
michael@0: if (eOrigin_TableRow == mOrigin) {
michael@0: /* If we originate from the row, then make the row the origin. */
michael@0: mRow.mRect.MoveTo(0, 0);
michael@0: }
michael@0: //else: Use row group's coord system -> no translation necessary
michael@0:
michael@0: for (nsTableCellFrame* cell = aFrame->GetFirstCell(); cell; cell = cell->GetNextCell()) {
michael@0: //Translate to use the same coord system as mRow.
michael@0: mCellRect = cell->GetRect() + mRow.mRect.TopLeft() + mRenderPt;
michael@0: if (mCellRect.Intersects(mDirtyRect)) {
michael@0: nsresult rv = PaintCell(cell, aPassThrough || cell->IsPseudoStackingContextFromStyle());
michael@0: if (NS_FAILED(rv)) return rv;
michael@0: }
michael@0: }
michael@0:
michael@0: /* Unload row data */
michael@0: mRow.Clear();
michael@0: return NS_OK;
michael@0: }
michael@0:
michael@0: nsresult
michael@0: TableBackgroundPainter::PaintCell(nsTableCellFrame* aCell,
michael@0: bool aPassSelf)
michael@0: {
michael@0: NS_PRECONDITION(aCell, "null frame");
michael@0:
michael@0: const nsStyleTableBorder* cellTableStyle;
michael@0: cellTableStyle = aCell->StyleTableBorder();
michael@0: if (!(NS_STYLE_TABLE_EMPTY_CELLS_SHOW == cellTableStyle->mEmptyCells ||
michael@0: NS_STYLE_TABLE_EMPTY_CELLS_SHOW_BACKGROUND == cellTableStyle->mEmptyCells)
michael@0: && aCell->GetContentEmpty() && !mIsBorderCollapse) {
michael@0: return NS_OK;
michael@0: }
michael@0:
michael@0: int32_t colIndex;
michael@0: aCell->GetColIndex(colIndex);
michael@0: NS_ASSERTION(colIndex < int32_t(mNumCols), "prevent array boundary violation");
michael@0: if (int32_t(mNumCols) <= colIndex)
michael@0: return NS_OK;
michael@0:
michael@0: //Paint column group background
michael@0: if (mCols && mCols[colIndex].mColGroup && mCols[colIndex].mColGroup->IsVisible()) {
michael@0: nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
michael@0: mCols[colIndex].mColGroup->mFrame, mDirtyRect,
michael@0: mCols[colIndex].mColGroup->mRect + mRenderPt,
michael@0: mCols[colIndex].mColGroup->mFrame->StyleContext(),
michael@0: *mCols[colIndex].mColGroup->mBorder,
michael@0: mBGPaintFlags, &mCellRect);
michael@0: }
michael@0:
michael@0: //Paint column background
michael@0: if (mCols && mCols[colIndex].mCol.IsVisible()) {
michael@0: nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
michael@0: mCols[colIndex].mCol.mFrame, mDirtyRect,
michael@0: mCols[colIndex].mCol.mRect + mRenderPt,
michael@0: mCols[colIndex].mCol.mFrame->StyleContext(),
michael@0: *mCols[colIndex].mCol.mBorder,
michael@0: mBGPaintFlags, &mCellRect);
michael@0: }
michael@0:
michael@0: //Paint row group background
michael@0: if (mRowGroup.IsVisible()) {
michael@0: nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
michael@0: mRowGroup.mFrame, mDirtyRect,
michael@0: mRowGroup.mRect + mRenderPt,
michael@0: mRowGroup.mFrame->StyleContext(),
michael@0: *mRowGroup.mBorder,
michael@0: mBGPaintFlags, &mCellRect);
michael@0: }
michael@0:
michael@0: //Paint row background
michael@0: if (mRow.IsVisible()) {
michael@0: nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
michael@0: mRow.mFrame, mDirtyRect,
michael@0: mRow.mRect + mRenderPt,
michael@0: mRow.mFrame->StyleContext(),
michael@0: *mRow.mBorder,
michael@0: mBGPaintFlags, &mCellRect);
michael@0: }
michael@0:
michael@0: //Paint cell background in border-collapse unless we're just passing
michael@0: if (mIsBorderCollapse && !aPassSelf) {
michael@0: aCell->PaintCellBackground(mRenderingContext, mDirtyRect,
michael@0: mCellRect.TopLeft(), mBGPaintFlags);
michael@0: }
michael@0:
michael@0: return NS_OK;
michael@0: }