nsresult TableBackgroundPainter::PaintTableFrame(nsTableFrame* aTableFrame, nsTableRowGroupFrame* aFirstRowGroup, nsTableRowGroupFrame* aLastRowGroup, const nsMargin& aDeflate) { NS_PRECONDITION(aTableFrame, "null frame"); TableBackgroundData tableData; tableData.SetFull(aTableFrame); tableData.mRect.MoveTo(0,0); //using table's coords tableData.mRect.Deflate(aDeflate); if (mIsBorderCollapse && tableData.ShouldSetBCBorder()) { if (aFirstRowGroup && aLastRowGroup && mNumCols > 0) { //only handle non-degenerate tables; we need a more robust BC model //to make degenerate tables' borders reasonable to deal with nsMargin border, tempBorder; nsTableColFrame* colFrame = aTableFrame->GetColFrame(mNumCols - 1); if (colFrame) { colFrame->GetContinuousBCBorderWidth(tempBorder); } border.right = tempBorder.right; aLastRowGroup->GetContinuousBCBorderWidth(tempBorder); border.bottom = tempBorder.bottom; nsTableRowFrame* rowFrame = aFirstRowGroup->GetFirstRow(); if (rowFrame) { rowFrame->GetContinuousBCBorderWidth(tempBorder); border.top = tempBorder.top; } border.left = aTableFrame->GetContinuousLeftBCBorderWidth(); nsresult rv = tableData.SetBCBorder(border, this); if (NS_FAILED(rv)) { tableData.Destroy(mPresContext); return rv; } } } if (tableData.IsVisible()) { nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext, tableData.mFrame, mDirtyRect, tableData.mRect + mRenderPt, tableData.mFrame->StyleContext(), *tableData.mBorder, mBGPaintFlags); } tableData.Destroy(mPresContext); return NS_OK; }
DrawResult TableBackgroundPainter::PaintCell(nsTableCellFrame* aCell, const TableBackgroundData& aRowGroupBGData, const TableBackgroundData& aRowBGData, nsRect& aCellBGRect, nsRect& aRowBGRect, nsRect& aRowGroupBGRect, nsRect& aColBGRect, bool aPassSelf) { MOZ_ASSERT(aCell, "null frame"); const nsStyleTableBorder* cellTableStyle; cellTableStyle = aCell->StyleTableBorder(); if (NS_STYLE_TABLE_EMPTY_CELLS_SHOW != cellTableStyle->mEmptyCells && aCell->GetContentEmpty() && !mIsBorderCollapse) { return DrawResult::SUCCESS; } int32_t colIndex; aCell->GetColIndex(colIndex); // We're checking mNumCols instead of mCols.Length() here because mCols can // be empty even if mNumCols > 0. NS_ASSERTION(size_t(colIndex) < mNumCols, "out-of-bounds column index"); if (size_t(colIndex) >= mNumCols) { return DrawResult::SUCCESS; } // If callers call PaintRowGroup or PaintRow directly, we haven't processed // our columns. Ignore column / col group backgrounds in that case. bool haveColumns = !mCols.IsEmpty(); DrawResult result = DrawResult::SUCCESS; //Paint column group background if (haveColumns && mCols[colIndex].mColGroup.IsVisible()) { DrawResult colGroupResult = nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext, mCols[colIndex].mColGroup.mFrame, mDirtyRect, mCols[colIndex].mColGroup.mRect + mRenderPt, mCols[colIndex].mColGroup.mFrame->StyleContext(), mCols[colIndex].mColGroup.StyleBorder(mZeroBorder), mBGPaintFlags, &aColBGRect); UpdateDrawResult(&result, colGroupResult); } //Paint column background if (haveColumns && mCols[colIndex].mCol.IsVisible()) { DrawResult colResult = nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext, mCols[colIndex].mCol.mFrame, mDirtyRect, mCols[colIndex].mCol.mRect + mRenderPt, mCols[colIndex].mCol.mFrame->StyleContext(), mCols[colIndex].mCol.StyleBorder(mZeroBorder), mBGPaintFlags, &aColBGRect); UpdateDrawResult(&result, colResult); } //Paint row group background if (aRowGroupBGData.IsVisible()) { DrawResult rowGroupResult = nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext, aRowGroupBGData.mFrame, mDirtyRect, aRowGroupBGData.mRect + mRenderPt, aRowGroupBGData.mFrame->StyleContext(), aRowGroupBGData.StyleBorder(mZeroBorder), mBGPaintFlags, &aRowGroupBGRect); UpdateDrawResult(&result, rowGroupResult); } //Paint row background if (aRowBGData.IsVisible()) { DrawResult rowResult = nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext, aRowBGData.mFrame, mDirtyRect, aRowBGData.mRect + mRenderPt, aRowBGData.mFrame->StyleContext(), aRowBGData.StyleBorder(mZeroBorder), mBGPaintFlags, &aRowBGRect); UpdateDrawResult(&result, rowResult); } //Paint cell background in border-collapse unless we're just passing if (mIsBorderCollapse && !aPassSelf) { DrawResult cellResult = aCell->PaintCellBackground(mRenderingContext, mDirtyRect, aCellBGRect.TopLeft(), mBGPaintFlags); UpdateDrawResult(&result, cellResult); } return result; }
DrawResult TableBackgroundPainter::PaintRow(nsTableRowFrame* aFrame, const TableBackgroundData& aRowGroupBGData, TableBackgroundData aRowBGData, bool aPassThrough) { MOZ_ASSERT(aFrame, "null frame"); /* Load row data */ WritingMode wm = aFrame->GetWritingMode(); if (aPassThrough) { aRowBGData.MakeInvisible(); } else { if (mIsBorderCollapse && aRowBGData.ShouldSetBCBorder()) { LogicalMargin border(wm); nsTableRowFrame* nextRow = aFrame->GetNextRow(); if (nextRow) { //outer bStart after us is inner bEnd for us border.BEnd(wm) = nextRow->GetOuterBStartContBCBorderWidth(); } else { //acquire rg's bEnd border nsTableRowGroupFrame* rowGroup = static_cast<nsTableRowGroupFrame*>(aFrame->GetParent()); rowGroup->GetContinuousBCBorderWidth(wm, border); } //get the rest of the borders; will overwrite all but bEnd aFrame->GetContinuousBCBorderWidth(wm, border); aRowBGData.SetBCBorder(border.GetPhysicalMargin(wm)); } aPassThrough = !aRowBGData.IsVisible(); } /* Translate */ if (eOrigin_TableRow == mOrigin) { /* If we originate from the row, then make the row the origin. */ aRowBGData.mRect.MoveTo(0, 0); } //else: Use row group's coord system -> no translation necessary DrawResult result = DrawResult::SUCCESS; for (nsTableCellFrame* cell = aFrame->GetFirstCell(); cell; cell = cell->GetNextCell()) { nsRect cellBGRect, rowBGRect, rowGroupBGRect, colBGRect; ComputeCellBackgrounds(cell, aRowGroupBGData, aRowBGData, cellBGRect, rowBGRect, rowGroupBGRect, colBGRect); // Find the union of all the cell background layers. nsRect combinedRect(cellBGRect); combinedRect.UnionRect(combinedRect, rowBGRect); combinedRect.UnionRect(combinedRect, rowGroupBGRect); combinedRect.UnionRect(combinedRect, colBGRect); if (combinedRect.Intersects(mDirtyRect)) { bool passCell = aPassThrough || cell->IsPseudoStackingContextFromStyle(); DrawResult cellResult = PaintCell(cell, aRowGroupBGData, aRowBGData, cellBGRect, rowBGRect, rowGroupBGRect, colBGRect, passCell); UpdateDrawResult(&result, cellResult); } } return result; }
DrawResult TableBackgroundPainter::PaintRowGroup(nsTableRowGroupFrame* aFrame, TableBackgroundData aRowGroupBGData, bool aPassThrough) { MOZ_ASSERT(aFrame, "null frame"); nsTableRowFrame* firstRow = aFrame->GetFirstRow(); WritingMode wm = aFrame->GetWritingMode(); /* Load row group data */ if (aPassThrough) { aRowGroupBGData.MakeInvisible(); } else { if (mIsBorderCollapse && aRowGroupBGData.ShouldSetBCBorder()) { LogicalMargin border(wm); if (firstRow) { //pick up first row's bstart border (= rg bstart border) firstRow->GetContinuousBCBorderWidth(wm, border); /* (row group doesn't store its bstart border) */ } //overwrite sides+bottom borders with rg's own aFrame->GetContinuousBCBorderWidth(wm, border); aRowGroupBGData.SetBCBorder(border.GetPhysicalMargin(wm)); } aPassThrough = !aRowGroupBGData.IsVisible(); } /* translate everything into row group coord system*/ if (eOrigin_TableRowGroup != mOrigin) { TranslateContext(aRowGroupBGData.mRect.x, aRowGroupBGData.mRect.y); } nsRect rgRect = aRowGroupBGData.mRect; aRowGroupBGData.mRect.MoveTo(0, 0); /* Find the right row to start with */ // Note that mDirtyRect - mRenderPt is guaranteed to be in the row // group's coordinate system here, so passing its .y to // GetFirstRowContaining is ok. nscoord overflowAbove; nsIFrame* cursor = aFrame->GetFirstRowContaining(mDirtyRect.y - mRenderPt.y, &overflowAbove); // Sadly, it seems like there may be non-row frames in there... or something? // There are certainly null-checks in GetFirstRow() and GetNextRow(). :( while (cursor && cursor->GetType() != nsGkAtoms::tableRowFrame) { cursor = cursor->GetNextSibling(); } // It's OK if cursor is null here. nsTableRowFrame* row = static_cast<nsTableRowFrame*>(cursor); if (!row) { // No useful cursor; just start at the top. Don't bother to set up a // cursor; if we've gotten this far then we've already built the display // list for the rowgroup, so not having a cursor means that there's some // good reason we don't have a cursor and we shouldn't create one here. row = firstRow; } DrawResult result = DrawResult::SUCCESS; /* Finally paint */ for (; row; row = row->GetNextRow()) { TableBackgroundData rowBackgroundData(row); // Be sure to consider our positions both pre- and post-relative // positioning, since we potentially need to paint at both places. nscoord rowY = std::min(rowBackgroundData.mRect.y, row->GetNormalPosition().y); // Intersect wouldn't handle rowspans. if (cursor && (mDirtyRect.YMost() - mRenderPt.y) <= (rowY - overflowAbove)) { // All done; cells originating in later rows can't intersect mDirtyRect. break; } DrawResult rowResult = PaintRow(row, aRowGroupBGData, rowBackgroundData, aPassThrough || row->IsPseudoStackingContextFromStyle()); UpdateDrawResult(&result, rowResult); } /* translate back into table coord system */ if (eOrigin_TableRowGroup != mOrigin) { TranslateContext(-rgRect.x, -rgRect.y); } return result; }