diff --git a/mozilla/content/shared/src/nsStyleStruct.cpp b/mozilla/content/shared/src/nsStyleStruct.cpp index d4d217a5c21..ccbb0245ba5 100644 --- a/mozilla/content/shared/src/nsStyleStruct.cpp +++ b/mozilla/content/shared/src/nsStyleStruct.cpp @@ -538,16 +538,24 @@ void nsStyleBorder::RecalcData() } if ((mBorderStyle[NS_SIDE_TOP] & BORDER_COLOR_DEFINED) == 0) { - mBorderStyle[NS_SIDE_TOP] = BORDER_COLOR_DEFINED | BORDER_COLOR_FOREGROUND; + NS_ASSERTION(!(mBorderStyle[NS_SIDE_TOP] & BORDER_COLOR_SPECIAL), + "Clearing special border because BORDER_COLOR_DEFINED is not set"); + SetBorderToForeground(NS_SIDE_TOP); } if ((mBorderStyle[NS_SIDE_BOTTOM] & BORDER_COLOR_DEFINED) == 0) { - mBorderStyle[NS_SIDE_BOTTOM] = BORDER_COLOR_DEFINED | BORDER_COLOR_FOREGROUND; + NS_ASSERTION(!(mBorderStyle[NS_SIDE_BOTTOM] & BORDER_COLOR_SPECIAL), + "Clearing special border because BORDER_COLOR_DEFINED is not set"); + SetBorderToForeground(NS_SIDE_BOTTOM); } - if ((mBorderStyle[NS_SIDE_LEFT]& BORDER_COLOR_DEFINED) == 0) { - mBorderStyle[NS_SIDE_LEFT] = BORDER_COLOR_DEFINED | BORDER_COLOR_FOREGROUND; + if ((mBorderStyle[NS_SIDE_LEFT] & BORDER_COLOR_DEFINED) == 0) { + NS_ASSERTION(!(mBorderStyle[NS_SIDE_LEFT] & BORDER_COLOR_SPECIAL), + "Clearing special border because BORDER_COLOR_DEFINED is not set"); + SetBorderToForeground(NS_SIDE_LEFT); } if ((mBorderStyle[NS_SIDE_RIGHT] & BORDER_COLOR_DEFINED) == 0) { - mBorderStyle[NS_SIDE_RIGHT] = BORDER_COLOR_DEFINED | BORDER_COLOR_FOREGROUND; + NS_ASSERTION(!(mBorderStyle[NS_SIDE_RIGHT] & BORDER_COLOR_SPECIAL), + "Clearing special border because BORDER_COLOR_DEFINED is not set"); + SetBorderToForeground(NS_SIDE_RIGHT); } } diff --git a/mozilla/layout/base/nsCSSRendering.cpp b/mozilla/layout/base/nsCSSRendering.cpp index f7d3430e164..064efc0aafa 100644 --- a/mozilla/layout/base/nsCSSRendering.cpp +++ b/mozilla/layout/base/nsCSSRendering.cpp @@ -2716,7 +2716,8 @@ nsCSSRendering::PaintBackground(nsIPresContext* aPresContext, const nsRect& aBorderArea, const nsStyleBorder& aBorder, const nsStylePadding& aPadding, - PRBool aUsePrintSettings) + PRBool aUsePrintSettings, + nsRect* aBGClipRect) { NS_PRECONDITION(aForFrame, "Frame is expected to be provided to PaintBackground"); @@ -2744,7 +2745,7 @@ nsCSSRendering::PaintBackground(nsIPresContext* aPresContext, if (!isCanvas) { PaintBackgroundWithSC(aPresContext, aRenderingContext, aForFrame, aDirtyRect, aBorderArea, *color, aBorder, - aPadding, aUsePrintSettings); + aPadding, aUsePrintSettings, aBGClipRect); return; } @@ -2787,7 +2788,7 @@ nsCSSRendering::PaintBackground(nsIPresContext* aPresContext, PaintBackgroundWithSC(aPresContext, aRenderingContext, aForFrame, aDirtyRect, aBorderArea, canvasColor, - aBorder, aPadding, aUsePrintSettings); + aBorder, aPadding, aUsePrintSettings, aBGClipRect); } void @@ -2799,7 +2800,8 @@ nsCSSRendering::PaintBackgroundWithSC(nsIPresContext* aPresContext, const nsStyleBackground& aColor, const nsStyleBorder& aBorder, const nsStylePadding& aPadding, - PRBool aUsePrintSettings) + PRBool aUsePrintSettings, + nsRect* aBGClipRect) { NS_PRECONDITION(aForFrame, "Frame is expected to be provided to PaintBackground"); @@ -2825,14 +2827,20 @@ nsCSSRendering::PaintBackgroundWithSC(nsIPresContext* aPresContext, } } - // The background is rendered over the 'background-clip' area. - nsRect bgClipArea(aBorderArea); - if (aColor.mBackgroundClip != NS_STYLE_BG_CLIP_BORDER) { - NS_ASSERTION(aColor.mBackgroundClip == NS_STYLE_BG_CLIP_PADDING, - "unknown background-clip value"); - nsMargin border; - aBorder.GetBorder(border); - bgClipArea.Deflate(border); + nsRect bgClipArea; + if (aBGClipRect) { + bgClipArea = *aBGClipRect; + } + else { + // The background is rendered over the 'background-clip' area. + bgClipArea = aBorderArea; + if (aColor.mBackgroundClip != NS_STYLE_BG_CLIP_BORDER) { + NS_ASSERTION(aColor.mBackgroundClip == NS_STYLE_BG_CLIP_PADDING, + "unknown background-clip value"); + nsMargin border; + aBorder.GetBorder(border); + bgClipArea.Deflate(border); + } } // The actual dirty rect is the intersection of the 'background-clip' @@ -3186,41 +3194,41 @@ nsCSSRendering::PaintBackgroundWithSC(nsIPresContext* aPresContext, // first do the horizontal case nscoord x0, x1; + // For scrolling attachment, the anchor is within the 'background-clip' + // For fixed attachment, the anchor is within the bounds of the nearest + // scrolling ancestor (or the viewport) + x0 = (NS_STYLE_BG_ATTACHMENT_SCROLL == aColor.mBackgroundAttachment) ? + bgClipArea.x : 0; if (repeat & NS_STYLE_BG_REPEAT_X) { // When tiling in the x direction, adjust the starting position of the // tile to account for dirtyRect.x. When tiling in x, the anchor.x value // will be a negative value used to adjust the starting coordinate. - x0 = bgClipArea.x + anchor.x + ((dirtyRect.x - (bgClipArea.x + anchor.x)) / tileWidth) * tileWidth; + x0 += anchor.x + + ((dirtyRect.x - (bgClipArea.x + anchor.x)) / tileWidth) * tileWidth; x1 = x0 + ((dirtyRect.x + dirtyRect.width - x0 + tileWidth - 1) / tileWidth) * tileWidth; } else { - // For scrolling attachment, the anchor is within the 'background-clip' - // For fixed attachment, the anchor is within the bounds of the nearest - // scrolling ancestor (or the viewport) - x0 = anchor.x; - if (NS_STYLE_BG_ATTACHMENT_SCROLL == aColor.mBackgroundAttachment) { - x0 += bgClipArea.x; - } + x0 += anchor.x; x1 = x0 + tileWidth; } // now do all that again with the vertical case nscoord y0, y1; + // For scrolling attachment, the anchor is within the 'background-clip' + // For fixed attachment, the anchor is within the bounds of the nearest + // scrolling ancestor (or the viewport) + y0 = (NS_STYLE_BG_ATTACHMENT_SCROLL == aColor.mBackgroundAttachment) ? + bgClipArea.y : 0; if (repeat & NS_STYLE_BG_REPEAT_Y) { // When tiling in the y direction, adjust the starting position of the // tile to account for dirtyRect.y. When tiling in y, the anchor.y value // will be a negative value used to adjust the starting coordinate. - y0 = bgClipArea.y + anchor.y + ((dirtyRect.y - (bgClipArea.y + anchor.y)) / tileHeight) * tileHeight; + y0 += anchor.y + + ((dirtyRect.y - (bgClipArea.y + anchor.y)) / tileHeight) * tileHeight; y1 = y0 + ((dirtyRect.y + dirtyRect.height - y0 + tileHeight - 1) / tileHeight) * tileHeight; } else { - // For scrolling attachment, the anchor is within the 'background-clip' - // For fixed attachment, the anchor is within the bounds of the nearest - // scrolling ancestor (or the viewport) - y0 = anchor.y; - if (NS_STYLE_BG_ATTACHMENT_SCROLL == aColor.mBackgroundAttachment) { - y0 += bgClipArea.y; - } + y0 += anchor.y; y1 = y0 + tileHeight; } diff --git a/mozilla/layout/base/nsCSSRendering.h b/mozilla/layout/base/nsCSSRendering.h index 8f4f2e6c895..f0b45d87ade 100644 --- a/mozilla/layout/base/nsCSSRendering.h +++ b/mozilla/layout/base/nsCSSRendering.h @@ -140,7 +140,8 @@ public: const nsRect& aBorderArea, const nsStyleBorder& aBorder, const nsStylePadding& aPadding, - PRBool aUsePrintSettings); + PRBool aUsePrintSettings, + nsRect* aBGClipRect = nsnull); /** * Same as |PaintBackground|, except using the provided style context @@ -155,7 +156,9 @@ public: const nsStyleBackground& aColor, const nsStyleBorder& aBorder, const nsStylePadding& aPadding, - PRBool aUsePrintSettings=PR_FALSE); + PRBool aUsePrintSettings = PR_FALSE, + nsRect* aBGClipRect = nsnull); + /** * Called by the presShell when painting is finished, so we can clear our * inline background data cache. diff --git a/mozilla/layout/html/document/src/html.css b/mozilla/layout/html/document/src/html.css index f992dbc1bd3..e861052fd8a 100644 --- a/mozilla/layout/html/document/src/html.css +++ b/mozilla/layout/html/document/src/html.css @@ -150,7 +150,7 @@ plaintext, xmp, pre { table { display: table; - border-spacing: 2px; + border-spacing: 2px; border-collapse: separate; margin-top: 0; margin-bottom: 0; @@ -170,11 +170,6 @@ table[align="right"] { table[rules] { border-collapse: collapse; } - -/* make sure backgrounds are inherited in tables -- see bug 4510 */ -td, th, tr { - background: inherit; -} /* caption inherits from table not table-outer */ caption { diff --git a/mozilla/layout/html/document/src/quirk.css b/mozilla/layout/html/document/src/quirk.css index e1100e67c6c..9700d3b86ed 100644 --- a/mozilla/layout/html/document/src/quirk.css +++ b/mozilla/layout/html/document/src/quirk.css @@ -110,6 +110,10 @@ table { font-variant: -moz-initial; } +/* make sure backgrounds are inherited in tables -- see bug 4510*/ +td, th, tr { + background: inherit; +} /* Quirk: collapse top margin of BODY and TD and bottom margin of TD */ diff --git a/mozilla/layout/html/style/src/nsCSSRendering.cpp b/mozilla/layout/html/style/src/nsCSSRendering.cpp index f7d3430e164..064efc0aafa 100644 --- a/mozilla/layout/html/style/src/nsCSSRendering.cpp +++ b/mozilla/layout/html/style/src/nsCSSRendering.cpp @@ -2716,7 +2716,8 @@ nsCSSRendering::PaintBackground(nsIPresContext* aPresContext, const nsRect& aBorderArea, const nsStyleBorder& aBorder, const nsStylePadding& aPadding, - PRBool aUsePrintSettings) + PRBool aUsePrintSettings, + nsRect* aBGClipRect) { NS_PRECONDITION(aForFrame, "Frame is expected to be provided to PaintBackground"); @@ -2744,7 +2745,7 @@ nsCSSRendering::PaintBackground(nsIPresContext* aPresContext, if (!isCanvas) { PaintBackgroundWithSC(aPresContext, aRenderingContext, aForFrame, aDirtyRect, aBorderArea, *color, aBorder, - aPadding, aUsePrintSettings); + aPadding, aUsePrintSettings, aBGClipRect); return; } @@ -2787,7 +2788,7 @@ nsCSSRendering::PaintBackground(nsIPresContext* aPresContext, PaintBackgroundWithSC(aPresContext, aRenderingContext, aForFrame, aDirtyRect, aBorderArea, canvasColor, - aBorder, aPadding, aUsePrintSettings); + aBorder, aPadding, aUsePrintSettings, aBGClipRect); } void @@ -2799,7 +2800,8 @@ nsCSSRendering::PaintBackgroundWithSC(nsIPresContext* aPresContext, const nsStyleBackground& aColor, const nsStyleBorder& aBorder, const nsStylePadding& aPadding, - PRBool aUsePrintSettings) + PRBool aUsePrintSettings, + nsRect* aBGClipRect) { NS_PRECONDITION(aForFrame, "Frame is expected to be provided to PaintBackground"); @@ -2825,14 +2827,20 @@ nsCSSRendering::PaintBackgroundWithSC(nsIPresContext* aPresContext, } } - // The background is rendered over the 'background-clip' area. - nsRect bgClipArea(aBorderArea); - if (aColor.mBackgroundClip != NS_STYLE_BG_CLIP_BORDER) { - NS_ASSERTION(aColor.mBackgroundClip == NS_STYLE_BG_CLIP_PADDING, - "unknown background-clip value"); - nsMargin border; - aBorder.GetBorder(border); - bgClipArea.Deflate(border); + nsRect bgClipArea; + if (aBGClipRect) { + bgClipArea = *aBGClipRect; + } + else { + // The background is rendered over the 'background-clip' area. + bgClipArea = aBorderArea; + if (aColor.mBackgroundClip != NS_STYLE_BG_CLIP_BORDER) { + NS_ASSERTION(aColor.mBackgroundClip == NS_STYLE_BG_CLIP_PADDING, + "unknown background-clip value"); + nsMargin border; + aBorder.GetBorder(border); + bgClipArea.Deflate(border); + } } // The actual dirty rect is the intersection of the 'background-clip' @@ -3186,41 +3194,41 @@ nsCSSRendering::PaintBackgroundWithSC(nsIPresContext* aPresContext, // first do the horizontal case nscoord x0, x1; + // For scrolling attachment, the anchor is within the 'background-clip' + // For fixed attachment, the anchor is within the bounds of the nearest + // scrolling ancestor (or the viewport) + x0 = (NS_STYLE_BG_ATTACHMENT_SCROLL == aColor.mBackgroundAttachment) ? + bgClipArea.x : 0; if (repeat & NS_STYLE_BG_REPEAT_X) { // When tiling in the x direction, adjust the starting position of the // tile to account for dirtyRect.x. When tiling in x, the anchor.x value // will be a negative value used to adjust the starting coordinate. - x0 = bgClipArea.x + anchor.x + ((dirtyRect.x - (bgClipArea.x + anchor.x)) / tileWidth) * tileWidth; + x0 += anchor.x + + ((dirtyRect.x - (bgClipArea.x + anchor.x)) / tileWidth) * tileWidth; x1 = x0 + ((dirtyRect.x + dirtyRect.width - x0 + tileWidth - 1) / tileWidth) * tileWidth; } else { - // For scrolling attachment, the anchor is within the 'background-clip' - // For fixed attachment, the anchor is within the bounds of the nearest - // scrolling ancestor (or the viewport) - x0 = anchor.x; - if (NS_STYLE_BG_ATTACHMENT_SCROLL == aColor.mBackgroundAttachment) { - x0 += bgClipArea.x; - } + x0 += anchor.x; x1 = x0 + tileWidth; } // now do all that again with the vertical case nscoord y0, y1; + // For scrolling attachment, the anchor is within the 'background-clip' + // For fixed attachment, the anchor is within the bounds of the nearest + // scrolling ancestor (or the viewport) + y0 = (NS_STYLE_BG_ATTACHMENT_SCROLL == aColor.mBackgroundAttachment) ? + bgClipArea.y : 0; if (repeat & NS_STYLE_BG_REPEAT_Y) { // When tiling in the y direction, adjust the starting position of the // tile to account for dirtyRect.y. When tiling in y, the anchor.y value // will be a negative value used to adjust the starting coordinate. - y0 = bgClipArea.y + anchor.y + ((dirtyRect.y - (bgClipArea.y + anchor.y)) / tileHeight) * tileHeight; + y0 += anchor.y + + ((dirtyRect.y - (bgClipArea.y + anchor.y)) / tileHeight) * tileHeight; y1 = y0 + ((dirtyRect.y + dirtyRect.height - y0 + tileHeight - 1) / tileHeight) * tileHeight; } else { - // For scrolling attachment, the anchor is within the 'background-clip' - // For fixed attachment, the anchor is within the bounds of the nearest - // scrolling ancestor (or the viewport) - y0 = anchor.y; - if (NS_STYLE_BG_ATTACHMENT_SCROLL == aColor.mBackgroundAttachment) { - y0 += bgClipArea.y; - } + y0 += anchor.y; y1 = y0 + tileHeight; } diff --git a/mozilla/layout/html/style/src/nsCSSRendering.h b/mozilla/layout/html/style/src/nsCSSRendering.h index 8f4f2e6c895..f0b45d87ade 100644 --- a/mozilla/layout/html/style/src/nsCSSRendering.h +++ b/mozilla/layout/html/style/src/nsCSSRendering.h @@ -140,7 +140,8 @@ public: const nsRect& aBorderArea, const nsStyleBorder& aBorder, const nsStylePadding& aPadding, - PRBool aUsePrintSettings); + PRBool aUsePrintSettings, + nsRect* aBGClipRect = nsnull); /** * Same as |PaintBackground|, except using the provided style context @@ -155,7 +156,9 @@ public: const nsStyleBackground& aColor, const nsStyleBorder& aBorder, const nsStylePadding& aPadding, - PRBool aUsePrintSettings=PR_FALSE); + PRBool aUsePrintSettings = PR_FALSE, + nsRect* aBGClipRect = nsnull); + /** * Called by the presShell when painting is finished, so we can clear our * inline background data cache. diff --git a/mozilla/layout/html/table/src/Makefile.in b/mozilla/layout/html/table/src/Makefile.in index 7842fe01a38..abbc8fc9752 100644 --- a/mozilla/layout/html/table/src/Makefile.in +++ b/mozilla/layout/html/table/src/Makefile.in @@ -52,6 +52,7 @@ CPPSRCS = \ nsTableOuterFrame.cpp \ nsTableRowFrame.cpp \ nsTableRowGroupFrame.cpp \ + nsTablePainter.cpp \ $(NULL) # we don't want the shared lib, but we want to force the creation of a static lib. diff --git a/mozilla/layout/html/table/src/nsCellMap.cpp b/mozilla/layout/html/table/src/nsCellMap.cpp index 077cd9b0154..9675d80853b 100644 --- a/mozilla/layout/html/table/src/nsCellMap.cpp +++ b/mozilla/layout/html/table/src/nsCellMap.cpp @@ -88,11 +88,11 @@ nsTableCellMap::nsTableCellMap(nsTableFrame& aTableFrame, NS_ASSERTION(orderedRowGroups.Count() == (PRInt32) numRowGroups,"problem in OrderRowGroups"); for (PRUint32 rgX = 0; rgX < numRowGroups; rgX++) { - nsTableRowGroupFrame* rgFrame = - aTableFrame.GetRowGroupFrame((nsIFrame*)orderedRowGroups.ElementAt(rgX)); + nsTableRowGroupFrame* rgFrame = + nsTableFrame::GetRowGroupFrame((nsIFrame*)orderedRowGroups.ElementAt(rgX)); if (rgFrame) { - nsTableRowGroupFrame* prior = (0 == rgX) - ? nsnull : aTableFrame.GetRowGroupFrame((nsIFrame*)orderedRowGroups.ElementAt(rgX - 1)); + nsTableRowGroupFrame* prior = (0 == rgX) + ? nsnull : nsTableFrame::GetRowGroupFrame((nsIFrame*)orderedRowGroups.ElementAt(rgX - 1)); InsertGroupCellMap(*rgFrame, prior); } } diff --git a/mozilla/layout/html/table/src/nsTableCellFrame.cpp b/mozilla/layout/html/table/src/nsTableCellFrame.cpp index 2bcfaf7d94c..4752f803e86 100644 --- a/mozilla/layout/html/table/src/nsTableCellFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableCellFrame.cpp @@ -40,6 +40,7 @@ #include "nsTableCellFrame.h" #include "nsTableFrame.h" #include "nsTableRowGroupFrame.h" +#include "nsTablePainter.h" #include "nsReflowPath.h" #include "nsStyleContext.h" #include "nsStyleConsts.h" @@ -376,30 +377,23 @@ nsTableCellFrame::PaintUnderlay(nsIPresContext& aPresContext, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, PRUint32& aFlags, - const nsStyleTableBorder& aCellTableStyle, const nsStyleBorder& aStyleBorder, const nsStylePadding& aStylePadding, - PRBool aVisibleBackground, - PRBool& aPaintChildren) + const nsStyleTableBorder& aCellTableStyle) { - if (aVisibleBackground) { - nsRect rect(0, 0, mRect.width, mRect.height); - nsCSSRendering::PaintBackground(&aPresContext, aRenderingContext, this, - aDirtyRect, rect, aStyleBorder, aStylePadding, - PR_TRUE); - // draw the border only when there is content or showing empty cells - if (!GetContentEmpty() || NS_STYLE_TABLE_EMPTY_CELLS_SHOW == aCellTableStyle.mEmptyCells) { - PRIntn skipSides = GetSkipSides(); - nsCSSRendering::PaintBorder(&aPresContext, aRenderingContext, this, - aDirtyRect, rect, aStyleBorder, mStyleContext, skipSides); - } + nsRect rect(0, 0, mRect.width, mRect.height); + nsCSSRendering::PaintBackground(&aPresContext, aRenderingContext, this, + aDirtyRect, rect, aStyleBorder, aStylePadding, + PR_TRUE); + PRIntn skipSides = GetSkipSides(); + if (NS_STYLE_TABLE_EMPTY_CELLS_SHOW == aCellTableStyle.mEmptyCells || + !GetContentEmpty()) { + nsCSSRendering::PaintBorder(&aPresContext, aRenderingContext, this, + aDirtyRect, rect, aStyleBorder, mStyleContext, skipSides); } - - // tell Paint to paint the children - aPaintChildren = PR_TRUE; } -NS_METHOD +NS_IMETHODIMP nsTableCellFrame::Paint(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, @@ -412,10 +406,9 @@ nsTableCellFrame::Paint(nsIPresContext* aPresContext, return NS_OK; } - PRBool paintChildren = PR_TRUE; + PRBool paintChildren = PR_TRUE; if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) { - PRBool paintBackground = PR_FALSE; const nsStyleBorder* myBorder = nsnull; const nsStylePadding* myPadding = nsnull; const nsStyleTableBorder* cellTableStyle = nsnull; @@ -425,19 +418,20 @@ nsTableCellFrame::Paint(nsIPresContext* aPresContext, myPadding = GetStylePadding(); cellTableStyle = GetStyleTableBorder(); - // paint the background when the cell is not empty or when showing empty cells or background - paintBackground = (!GetContentEmpty() || - NS_STYLE_TABLE_EMPTY_CELLS_SHOW == cellTableStyle->mEmptyCells || - NS_STYLE_TABLE_EMPTY_CELLS_SHOW_BACKGROUND == cellTableStyle->mEmptyCells); - } - - PaintUnderlay(*aPresContext, aRenderingContext, aDirtyRect, aFlags, *cellTableStyle, - *myBorder, *myPadding, paintBackground, paintChildren); + // draw the border & background only when there is content or showing empty cells + if (NS_STYLE_TABLE_EMPTY_CELLS_HIDE != cellTableStyle->mEmptyCells || + !GetContentEmpty()) { + PaintUnderlay(*aPresContext, aRenderingContext, aDirtyRect, aFlags, + *myBorder, *myPadding, *cellTableStyle); + } - if (vis->IsVisible()) { const nsStyleBackground* myColor = GetStyleBackground(); DecorateForSelection(aPresContext, aRenderingContext,myColor); //ignore return value } + + paintChildren = !(aFlags & NS_PAINT_FLAG_TABLE_CELL_BG_PASS); + //flags were for us; remove them for our children + aFlags &= ~ (NS_PAINT_FLAG_TABLE_CELL_BG_PASS | NS_PAINT_FLAG_TABLE_BG_PAINT); } #ifdef DEBUG @@ -931,7 +925,7 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext, const nsStylePosition* pos = GetStylePosition(); // calculate the min cell width - nscoord onePixel = NSIntPixelsToTwips(1, p2t); + nscoord onePixel = NSIntPixelsToTwips(1, p2t); nscoord smallestMinWidth = 0; if (eCompatibility_NavQuirks == compatMode) { if ((pos->mWidth.GetUnit() != eStyleUnit_Coord) && @@ -1332,14 +1326,14 @@ nsBCTableCellFrame::PaintUnderlay(nsIPresContext& aPresContext, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, PRUint32& aFlags, - const nsStyleTableBorder& aCellTableStyle, const nsStyleBorder& aStyleBorder, const nsStylePadding& aStylePadding, - PRBool aVisibleBackground, - PRBool& aPaintChildren) + const nsStyleTableBorder& aCellTableStyle) { - // Draw the background only during pass1. - if (aVisibleBackground && !(aFlags & BORDER_COLLAPSE_BACKGROUNDS)) { + if (!(aFlags & NS_PAINT_FLAG_TABLE_BG_PAINT) + /*direct call; not table-based paint*/ || + (aFlags & NS_PAINT_FLAG_TABLE_CELL_BG_PASS) + /*table cell background only pass*/) { // make border-width reflect border-collapse assigned border GET_PIXELS_TO_TWIPS(&aPresContext, p2t); nsMargin borderWidth; @@ -1363,7 +1357,4 @@ nsBCTableCellFrame::PaintUnderlay(nsIPresContext& aPresContext, PR_TRUE); // borders are painted by nsTableFrame } - - // don't paint the children if it's pass1 - aPaintChildren = (aFlags & BORDER_COLLAPSE_BACKGROUNDS); } diff --git a/mozilla/layout/html/table/src/nsTableCellFrame.h b/mozilla/layout/html/table/src/nsTableCellFrame.h index fd2082c2e91..83ffeda3087 100644 --- a/mozilla/layout/html/table/src/nsTableCellFrame.h +++ b/mozilla/layout/html/table/src/nsTableCellFrame.h @@ -289,16 +289,13 @@ protected: friend class nsTableRowFrame; - // paint backgrounds and borders (in separate border model) if aVisibleBackground, always set aPaintChildren virtual void PaintUnderlay(nsIPresContext& aPresContext, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, PRUint32& aFlags, - const nsStyleTableBorder& aCellTableStyle, const nsStyleBorder& aStyleBorder, const nsStylePadding& aStylePadding, - PRBool aVisibleBackground, - PRBool& aPaintChildren); + const nsStyleTableBorder& aCellTableStyle); nsresult DecorateForSelection(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, @@ -471,11 +468,9 @@ protected: nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, PRUint32& aFlags, - const nsStyleTableBorder& aCellTableStyle, const nsStyleBorder& aStyleBorder, const nsStylePadding& aStylePadding, - PRBool aVisibleBackground, - PRBool& aPaintChildren); + const nsStyleTableBorder& aCellTableStyle); private: diff --git a/mozilla/layout/html/table/src/nsTableColFrame.cpp b/mozilla/layout/html/table/src/nsTableColFrame.cpp index 8f14ebdefd2..84bdffc0721 100644 --- a/mozilla/layout/html/table/src/nsTableColFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableColFrame.cpp @@ -118,6 +118,24 @@ nsStyleCoord nsTableColFrame::GetStyleWidth() const return returnWidth; } +void nsTableColFrame::SetContinuousBCBorderWidth(PRUint8 aForSide, + BCPixelSize aPixelValue) +{ + switch (aForSide) { + case NS_SIDE_TOP: + mTopContBorderWidth = aPixelValue; + return; + case NS_SIDE_RIGHT: + mRightContBorderWidth = aPixelValue; + return; + case NS_SIDE_BOTTOM: + mBottomContBorderWidth = aPixelValue; + return; + default: + NS_ERROR("invalid side arg"); + } +} + void nsTableColFrame::ResetSizingInfo() { memset(mWidths, WIDTH_NOT_SET, NUM_WIDTHS * sizeof(PRInt32)); @@ -135,8 +153,6 @@ nsTableColFrame::Paint(nsIPresContext* aPresContext, if (NS_SUCCEEDED(IsVisibleForPainting(aPresContext, aRenderingContext, PR_FALSE, &isVisible)) && !isVisible) { return NS_OK; } - - // Standards mode background painting removed. See bug 4510 return NS_OK; } diff --git a/mozilla/layout/html/table/src/nsTableColFrame.h b/mozilla/layout/html/table/src/nsTableColFrame.h index a315cd95a00..89afa9debf4 100644 --- a/mozilla/layout/html/table/src/nsTableColFrame.h +++ b/mozilla/layout/html/table/src/nsTableColFrame.h @@ -39,6 +39,7 @@ #include "nscore.h" #include "nsContainerFrame.h" +#include "nsTablePainter.h" class nsVoidArray; class nsTableCellFrame; @@ -169,9 +170,26 @@ public: void ResetSizingInfo(); nscoord GetLeftBorderWidth(float* aPixelsToTwips = nsnull); - void SetLeftBorderWidth(nscoord aWidth); + void SetLeftBorderWidth(BCPixelSize aWidth); nscoord GetRightBorderWidth(float* aPixelsToTwips = nsnull); - void SetRightBorderWidth(nscoord aWidth); + void SetRightBorderWidth(BCPixelSize aWidth); + + /** + * Gets inner border widths before collapsing with cell borders + * Caller must get left border from previous column or from table + * GetContinuousBCBorderWidth will not overwrite aBorder.left + * see nsTablePainter about continuous borders + * + * @return outer right border width (left inner for next column) + */ + nscoord GetContinuousBCBorderWidth(float aPixelsToTwips, + nsMargin& aBorder); + /** + * Set full border widths before collapsing with cell borders + * @param aForSide - side to set; only valid for top, right, and bottom + */ + void SetContinuousBCBorderWidth(PRUint8 aForSide, + BCPixelSize aPixelValue); void Dump(PRInt32 aIndent); @@ -182,8 +200,13 @@ protected: // the starting index of the column (starting at 0) that this col object represents // PRUint32 mColIndex: 16; - PRUint32 mLeftBorderWidth: 8; // stored as pixels - PRUint32 mRightBorderWidth: 8; // stored as pixels + + // border width in pixels + BCPixelSize mLeftBorderWidth; + BCPixelSize mRightBorderWidth; + BCPixelSize mTopContBorderWidth; + BCPixelSize mRightContBorderWidth; + BCPixelSize mBottomContBorderWidth; // Widths including MIN_CON, DES_CON, FIX_CON, MIN_ADJ, DES_ADJ, FIX_ADJ, PCT, PCT_ADJ, MIN_PRO, FINAL // Widths including MIN_CON, DES_CON, FIX_CON, MIN_ADJ, DES_ADJ, FIX_ADJ, PCT, PCT_ADJ, MIN_PRO, FINAL // XXX these could be stored as pixels and converted to twips for a savings of 10 x 2 bytes. @@ -191,7 +214,7 @@ protected: }; inline PRInt32 nsTableColFrame::GetColIndex() const -{ +{ return mColIndex; } @@ -206,7 +229,7 @@ inline nscoord nsTableColFrame::GetLeftBorderWidth(float* aPixelsToTwips) return width; } -inline void nsTableColFrame::SetLeftBorderWidth(nscoord aWidth) +inline void nsTableColFrame::SetLeftBorderWidth(BCPixelSize aWidth) { mLeftBorderWidth = aWidth; } @@ -217,10 +240,23 @@ inline nscoord nsTableColFrame::GetRightBorderWidth(float* aPixelsToTwips) return width; } -inline void nsTableColFrame::SetRightBorderWidth(nscoord aWidth) +inline void nsTableColFrame::SetRightBorderWidth(BCPixelSize aWidth) { mRightBorderWidth = aWidth; } +inline nscoord +nsTableColFrame::GetContinuousBCBorderWidth(float aPixelsToTwips, + nsMargin& aBorder) +{ + aBorder.top = BC_BORDER_BOTTOM_HALF_COORD(aPixelsToTwips, + mTopContBorderWidth); + aBorder.right = BC_BORDER_LEFT_HALF_COORD(aPixelsToTwips, + mRightContBorderWidth); + aBorder.bottom = BC_BORDER_TOP_HALF_COORD(aPixelsToTwips, + mBottomContBorderWidth); + return BC_BORDER_RIGHT_HALF_COORD(aPixelsToTwips, mRightContBorderWidth); +} + #endif diff --git a/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp b/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp index 287302b06a6..cf49ce180f2 100644 --- a/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableColGroupFrame.cpp @@ -391,8 +391,6 @@ nsTableColGroupFrame::Paint(nsIPresContext* aPresContext, return NS_OK; } - // Standards mode background painting removed. See bug 4510 - PaintChildren(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer); return NS_OK; } @@ -646,6 +644,36 @@ void nsTableColGroupFrame::DeleteColFrame(nsIPresContext* aPresContext, nsTableC mFrames.DestroyFrame(aPresContext, aColFrame); } + +void nsTableColGroupFrame::SetContinuousBCBorderWidth(PRUint8 aForSide, + BCPixelSize aPixelValue) +{ + switch (aForSide) { + case NS_SIDE_TOP: + mTopContBorderWidth = aPixelValue; + return; + case NS_SIDE_BOTTOM: + mBottomContBorderWidth = aPixelValue; + return; + default: + NS_ERROR("invalid side arg"); + } +} + +void nsTableColGroupFrame::GetContinuousBCBorderWidth(float aPixelsToTwips, + nsMargin& aBorder) +{ + nsTableFrame* table; + nsTableFrame::GetTableFrame(this, table); + nsTableColFrame* col = table->GetColFrame(mStartColIndex + mColCount - 1); + col->GetContinuousBCBorderWidth(aPixelsToTwips, aBorder); + aBorder.top = BC_BORDER_BOTTOM_HALF_COORD(aPixelsToTwips, + mTopContBorderWidth); + aBorder.bottom = BC_BORDER_TOP_HALF_COORD(aPixelsToTwips, + mBottomContBorderWidth); + return; +} + /* ----- global methods ----- */ nsresult diff --git a/mozilla/layout/html/table/src/nsTableColGroupFrame.h b/mozilla/layout/html/table/src/nsTableColGroupFrame.h index ec9ff488bf1..6f5aa4ad673 100644 --- a/mozilla/layout/html/table/src/nsTableColGroupFrame.h +++ b/mozilla/layout/html/table/src/nsTableColGroupFrame.h @@ -40,9 +40,9 @@ #include "nscore.h" #include "nsHTMLContainerFrame.h" #include "nsTableColFrame.h" +#include "nsTablePainter.h" class nsTableColFrame; -class nsTableFrame; enum nsTableColGroupType { eColGroupContent = 0, // there is real col group content associated @@ -183,6 +183,21 @@ public: static void ResetColIndices(nsIFrame* aFirstColGroup, PRInt32 aFirstColIndex, nsIFrame* aStartColFrame = nsnull); + + /** + * Gets inner border widths before collapsing with cell borders + * Caller must get left border from previous column + * GetContinuousBCBorderWidth will not overwrite aBorder.left + * see nsTablePainter about continuous borders + */ + void GetContinuousBCBorderWidth(float aPixelsToTwips, + nsMargin& aBorder); + /** + * Set full border widths before collapsing with cell borders + * @param aForSide - side to set; only accepts top and bottom + */ + void SetContinuousBCBorderWidth(PRUint8 aForSide, + BCPixelSize aPixelValue); protected: nsTableColGroupFrame(); @@ -221,6 +236,10 @@ protected: PRInt32 mColCount; // the starting column index this col group represents. Must be >= 0. PRInt32 mStartColIndex; + + // border width in pixels + BCPixelSize mTopContBorderWidth; + BCPixelSize mBottomContBorderWidth; }; inline nsTableColGroupFrame::nsTableColGroupFrame() diff --git a/mozilla/layout/html/table/src/nsTableFrame.cpp b/mozilla/layout/html/table/src/nsTableFrame.cpp index 39747e63ccd..6a60f0021c6 100644 --- a/mozilla/layout/html/table/src/nsTableFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableFrame.cpp @@ -50,6 +50,7 @@ #include "nsTableRowFrame.h" #include "nsTableRowGroupFrame.h" #include "nsTableOuterFrame.h" +#include "nsTablePainter.h" #include "nsHTMLValue.h" #include "BasicTableLayoutStrategy.h" @@ -126,18 +127,21 @@ struct nsTableReflowState { nsTableFrame* table = (nsTableFrame*)aTableFrame.GetFirstInFlow(); nsMargin borderPadding = table->GetChildAreaOffset(&reflowState); + nscoord cellSpacingX = table->GetCellSpacingX(); - x = borderPadding.left; - y = borderPadding.top; + x = borderPadding.left + cellSpacingX; + y = borderPadding.top; //cellspacing added during reflow availSize.width = aAvailWidth; if (NS_UNCONSTRAINEDSIZE != availSize.width) { - availSize.width -= borderPadding.left + borderPadding.right; + availSize.width -= borderPadding.left + borderPadding.right + + (2 * cellSpacingX); } availSize.height = aAvailHeight; if (NS_UNCONSTRAINEDSIZE != availSize.height) { - availSize.height -= borderPadding.top + borderPadding.bottom + (2 * table->GetCellSpacingY()); + availSize.height -= borderPadding.top + borderPadding.bottom + + (2 * table->GetCellSpacingY()); } footerFrame = nsnull; @@ -288,7 +292,7 @@ nsTableFrame::~nsTableFrame() if (nsnull!=mCellMap) { delete mCellMap; mCellMap = nsnull; - } + } if (nsnull!=mTableLayoutStrategy) { delete mTableLayoutStrategy; @@ -1230,7 +1234,7 @@ void nsTableFrame::AppendRowGroups(nsIPresContext& aPresContext, nsTableRowGroupFrame* nsTableFrame::GetRowGroupFrame(nsIFrame* aFrame, - nsIAtom* aFrameTypeIn) const + nsIAtom* aFrameTypeIn) { nsIFrame* rgFrame = nsnull; nsIAtom* frameType = aFrameTypeIn; @@ -1386,43 +1390,54 @@ nsTableFrame::Paint(nsIPresContext* aPresContext, nsFramePaintLayer aWhichLayer, PRUint32 aFlags) { - PRBool visibleBCBorders = PR_FALSE; if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) { + TableBackgroundPainter painter(this, TableBackgroundPainter::eOrigin_Table, + aPresContext, aRenderingContext, aDirtyRect); + nsresult rv; + + if (eCompatibility_NavQuirks == aPresContext->CompatibilityMode()) { + nsMargin deflate(0,0,0,0); + if (IsBorderCollapse()) { + GET_PIXELS_TO_TWIPS(aPresContext, p2t); + BCPropertyData* propData = + (BCPropertyData*)nsTableFrame::GetProperty(aPresContext, + (nsIFrame*)this, + nsLayoutAtoms::tableBCProperty, + PR_FALSE); + if (propData) { + deflate.top = BC_BORDER_TOP_HALF_COORD(p2t, propData->mTopBorderWidth); + deflate.right = BC_BORDER_RIGHT_HALF_COORD(p2t, propData->mRightBorderWidth); + deflate.bottom = BC_BORDER_BOTTOM_HALF_COORD(p2t, propData->mBottomBorderWidth); + deflate.left = BC_BORDER_LEFT_HALF_COORD(p2t, propData->mLeftBorderWidth); + } + } + rv = painter.QuirksPaintTable(this, deflate); + if (NS_FAILED(rv)) return rv; + } + else { + rv = painter.PaintTable(this); + if (NS_FAILED(rv)) return rv; + } + if (GetStyleVisibility()->IsVisible()) { const nsStyleBorder* border = GetStyleBorder(); - const nsStylePadding* padding = GetStylePadding(); nsRect rect(0, 0, mRect.width, mRect.height); - - nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this, - aDirtyRect, rect, *border, *padding, - PR_TRUE); - - // paint the border here only for separate borders if (!IsBorderCollapse()) { PRIntn skipSides = GetSkipSides(); nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this, - aDirtyRect, rect, *border, mStyleContext, skipSides); + aDirtyRect, rect, *border, mStyleContext, + skipSides); } else { - visibleBCBorders = PR_TRUE; + PaintBCBorders(aPresContext, aRenderingContext, aDirtyRect); } } + aFlags |= NS_PAINT_FLAG_TABLE_BG_PAINT; + aFlags &= ~NS_PAINT_FLAG_TABLE_CELL_BG_PASS; } - // for collapsed borders paint the backgrounds of cells, but not their contents (that happens below) - PRUint32 flags = aFlags; - if (visibleBCBorders) { - flags &= ~BORDER_COLLAPSE_BACKGROUNDS; // set bit to 0 - } - PaintChildren(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer, flags); - - if (visibleBCBorders) { - // for collapsed borders, paint the borders and then the backgrounds of cell - // contents but not the backgrounds of the cells - PaintBCBorders(aPresContext, aRenderingContext, aDirtyRect); - flags |= BORDER_COLLAPSE_BACKGROUNDS; // set bit to 1 - PaintChildren(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer, flags); - } + PaintChildren(aPresContext, aRenderingContext, aDirtyRect, + aWhichLayer, aFlags); #ifdef DEBUG // for debug... @@ -1583,16 +1598,19 @@ nsTableFrame::AdjustSiblingsAfterReflow(nsIPresContext* aPresContext, return NS_OK; } -void +void nsTableFrame::SetColumnDimensions(nscoord aHeight, const nsMargin& aBorderPadding) { - nscoord colHeight = aHeight -= aBorderPadding.top + aBorderPadding.bottom; nscoord cellSpacingX = GetCellSpacingX(); + nscoord cellSpacingY = GetCellSpacingY(); + nscoord colHeight = aHeight -= aBorderPadding.top + aBorderPadding.bottom + + 2* cellSpacingY; nsIFrame* colGroupFrame = mColGroups.FirstChild(); PRInt32 colX = 0; - nsPoint colGroupOrigin(aBorderPadding.left + cellSpacingX, aBorderPadding.top); + nsPoint colGroupOrigin(aBorderPadding.left + cellSpacingX, + aBorderPadding.top + cellSpacingY); PRInt32 numCols = GetColCount(); while (nsnull != colGroupFrame) { nscoord colGroupWidth = 0; @@ -1606,19 +1624,19 @@ nsTableFrame::SetColumnDimensions(nscoord aHeight, nsRect colRect(colOrigin.x, colOrigin.y, colWidth, colHeight); colFrame->SetRect(colRect); colOrigin.x += colWidth + cellSpacingX; - - colGroupWidth += colWidth; - if (numCols - 1 != colX) { - colGroupWidth += cellSpacingX; - } + colGroupWidth += colWidth + cellSpacingX; colX++; } colFrame = colFrame->GetNextSibling(); } + if (colGroupWidth) { + colGroupWidth -= cellSpacingX; + } + nsRect colGroupRect(colGroupOrigin.x, colGroupOrigin.y, colGroupWidth, colHeight); colGroupFrame->SetRect(colGroupRect); colGroupFrame = colGroupFrame->GetNextSibling(); - colGroupOrigin.x += colGroupWidth; + colGroupOrigin.x += colGroupWidth + cellSpacingX; } } @@ -2881,7 +2899,7 @@ nsTableFrame::RecoverState(nsTableReflowState& aReflowState, if ((NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == display->mDisplay) && !aReflowState.footerFrame) { aReflowState.footerFrame = childFrame; - } + } else { if ((NS_STYLE_DISPLAY_TABLE_ROW_GROUP == display->mDisplay) && !aReflowState.firstBodySection) { @@ -3647,7 +3665,7 @@ nsTableFrame::DistributeHeightToRows(const nsHTMLReflowState& aReflowState, } yOriginRow += rowRect.height + cellSpacingY; yEndRG += rowRect.height + cellSpacingY; - } + } rowFrame = rowFrame->GetNextRow(); } if (amountUsed > 0) { @@ -5658,7 +5676,7 @@ nsTableFrame::CalcBCBorders(nsIPresContext& aPresContext) BCCellBorder lastTopBorder, lastBottomBorder; // horizontal borders indexed in x-direction (cols) BCCellBorders lastBottomBorders(damageArea.width + 1, damageArea.x); if (!lastBottomBorders.borders) ABORT0(); - PRBool startSeg; + PRBool startSeg, gotRowBorder; BCMapCellInfo info, ajaInfo; BCBorderOwner owner, ajaOwner; @@ -5680,6 +5698,7 @@ nsTableFrame::CalcBCBorders(nsIPresContext& aPresContext) PRBool bottomRowSpan = PR_FALSE; // see if lastTopBorder, lastBottomBorder need to be reset if (iter.IsNewRow()) { + gotRowBorder = PR_FALSE; lastTopBorder.Reset(info.rowIndex, info.rowSpan); lastBottomBorder.Reset(cellEndRowIndex + 1, info.rowSpan); } @@ -5722,7 +5741,7 @@ nsTableFrame::CalcBCBorders(nsIPresContext& aPresContext) // update lastTopBorder and see if a new segment starts startSeg = SetHorBorder(ownerBStyle, ownerWidth, ownerColor, tlCorner, lastTopBorder); // store the border segment in the cell map - tableCellMap->SetBCBorderEdge(NS_SIDE_TOP, *info.cellMap, 0, 0, colX, + tableCellMap->SetBCBorderEdge(NS_SIDE_TOP, *info.cellMap, 0, 0, colX, 1, owner, ownerWidth, startSeg); // update the affected borders of the cell, row, and table DivideBCBorderSize(ownerWidth, smallHalf, largeHalf); @@ -5733,6 +5752,44 @@ nsTableFrame::CalcBCBorders(nsIPresContext& aPresContext) info.topRow->SetTopBCBorderWidth(PR_MAX(smallHalf, info.topRow->GetTopBCBorderWidth())); } propData->mTopBorderWidth = LimitBorderWidth(PR_MAX(propData->mTopBorderWidth, (PRUint8)ownerWidth)); + //calculate column continuous borders + //we only need to do this once, so we'll do it only on the first row + CalcDominantBorder(this, cgFrame, colFrame, info.rg, info.topRow, + nsnull, PR_TRUE, NS_SIDE_TOP, PR_FALSE, t2p, + owner, ownerBStyle, ownerWidth, ownerColor); + ((nsTableColFrame*)colFrame)->SetContinuousBCBorderWidth(NS_SIDE_TOP, + ownerWidth); + if (numCols == cellEndColIndex + 1) { + CalcDominantBorder(this, cgFrame, colFrame, nsnull, nsnull, + nsnull, PR_TRUE, NS_SIDE_RIGHT, PR_FALSE, t2p, + owner, ownerBStyle, ownerWidth, ownerColor); + } + else { + CalcDominantBorder(nsnull, cgFrame, colFrame, nsnull, nsnull, + nsnull, PR_FALSE, NS_SIDE_RIGHT, PR_FALSE, t2p, + owner, ownerBStyle, ownerWidth, ownerColor); + } + ((nsTableColFrame*)colFrame)->SetContinuousBCBorderWidth(NS_SIDE_RIGHT, + ownerWidth); + } + //calculate continuous top first row & rowgroup border: special case + //because it must include the table in the collapse + CalcDominantBorder(this, nsnull, nsnull, info.rg, info.topRow, + nsnull, PR_TRUE, NS_SIDE_TOP, PR_FALSE, t2p, + owner, ownerBStyle, ownerWidth, ownerColor); + info.topRow->SetContinuousBCBorderWidth(NS_SIDE_TOP, ownerWidth); + if (info.cgRight) { + //calculate continuous top colgroup border once per colgroup + CalcDominantBorder(this, info.cg, nsnull, info.rg, info.topRow, + nsnull, PR_TRUE, NS_SIDE_TOP, PR_FALSE, t2p, + owner, ownerBStyle, ownerWidth, ownerColor); + info.cg->SetContinuousBCBorderWidth(NS_SIDE_TOP, ownerWidth); + } + if (0 == info.colIndex) { + CalcDominantBorder(this, info.cg, info.leftCol, nsnull, nsnull, + nsnull, PR_TRUE, NS_SIDE_LEFT, PR_FALSE, t2p, + owner, ownerBStyle, ownerWidth, ownerColor); + mBits.mLeftContBCBorder = ownerWidth; } } else { @@ -5760,10 +5817,10 @@ nsTableFrame::CalcBCBorders(nsIPresContext& aPresContext) nsTableRowFrame* rowFrame = nsnull; for (PRInt32 rowX = info.rowIndex; rowX <= cellEndRowIndex; rowX++) { rowFrame = (rowX == info.rowIndex) ? info.topRow : rowFrame->GetNextRow(); - CalcDominantBorder(this, info.cg, info.leftCol, info.rg, rowFrame, info.cell, PR_TRUE, NS_SIDE_LEFT, + CalcDominantBorder(this, info.cg, info.leftCol, info.rg, rowFrame, info.cell, PR_TRUE, NS_SIDE_LEFT, PR_FALSE, t2p, owner, ownerBStyle, ownerWidth, ownerColor); BCCornerInfo& tlCorner = (0 == rowX) ? topCorners[0] : bottomCorners[0]; // top left - tlCorner.Update(NS_SIDE_BOTTOM, owner, ownerBStyle, ownerWidth, ownerColor); + tlCorner.Update(NS_SIDE_BOTTOM, owner, ownerBStyle, ownerWidth, ownerColor); tableCellMap->SetBCBorderCorner(eTopLeft, *info.cellMap, iter.mRowGroupStart, rowX, 0, tlCorner.ownerSide, tlCorner.subWidth, tlCorner.bevel); bottomCorners[0].Set(NS_SIDE_TOP, owner, ownerBStyle, ownerWidth, ownerColor); // bottom left @@ -5781,6 +5838,17 @@ nsTableFrame::CalcBCBorders(nsIPresContext& aPresContext) info.leftCol->SetLeftBorderWidth(PR_MAX(smallHalf, info.leftCol->GetLeftBorderWidth())); } propData->mLeftBorderWidth = LimitBorderWidth(PR_MAX(propData->mLeftBorderWidth, ownerWidth)); + //get row continuous borders + CalcDominantBorder(this, info.cg, info.leftCol, info.rg, rowFrame, nsnull, PR_TRUE, NS_SIDE_LEFT, + PR_FALSE, t2p, owner, ownerBStyle, ownerWidth, ownerColor); + rowFrame->SetContinuousBCBorderWidth(NS_SIDE_LEFT, ownerWidth); + } + //get row group continuous borders + if (info.rgBottom) { //once per row group, so check for bottom + CalcDominantBorder(this, info.cg, info.leftCol, info.rg, nsnull, + nsnull, PR_TRUE, NS_SIDE_LEFT, PR_FALSE, t2p, + owner, ownerBStyle, ownerWidth, ownerColor); + info.rg->SetContinuousBCBorderWidth(NS_SIDE_LEFT, ownerWidth); } } @@ -5818,6 +5886,18 @@ nsTableFrame::CalcBCBorders(nsIPresContext& aPresContext) info.rightCol->SetRightBorderWidth(PR_MAX(largeHalf, info.rightCol->GetRightBorderWidth())); } propData->mRightBorderWidth = LimitBorderWidth(PR_MAX(propData->mRightBorderWidth, ownerWidth)); + //get row continuous borders + CalcDominantBorder(this, info.cg, info.rightCol, info.rg, rowFrame, + nsnull, PR_TRUE, NS_SIDE_RIGHT, PR_TRUE, t2p, + owner, ownerBStyle, ownerWidth, ownerColor); + rowFrame->SetContinuousBCBorderWidth(NS_SIDE_RIGHT, ownerWidth); + } + //get row group continuous borders + if (info.rgBottom) { //once per rg, so check for bottom + CalcDominantBorder(this, info.cg, info.rightCol, info.rg, nsnull, + nsnull, PR_TRUE, NS_SIDE_RIGHT, PR_TRUE, t2p, + owner, ownerBStyle, ownerWidth, ownerColor); + info.rg->SetContinuousBCBorderWidth(NS_SIDE_RIGHT, ownerWidth); } } else { @@ -5944,17 +6024,32 @@ nsTableFrame::CalcBCBorders(nsIPresContext& aPresContext) lastBottomBorder.index = cellEndRowIndex + 1; lastBottomBorder.span = info.rowSpan; lastBottomBorders[colX] = lastBottomBorder; + //get col continuous border + CalcDominantBorder(this, cgFrame, colFrame, info.rg, info.bottomRow, + nsnull, PR_TRUE, NS_SIDE_BOTTOM, PR_TRUE, t2p, + owner, ownerBStyle, ownerWidth, ownerColor); + ((nsTableColFrame*)colFrame)->SetContinuousBCBorderWidth(NS_SIDE_BOTTOM, + ownerWidth); } + //get row group/col group continuous border + CalcDominantBorder(this, nsnull, nsnull, info.rg, info.bottomRow, + nsnull, PR_TRUE, NS_SIDE_BOTTOM, PR_TRUE, t2p, + owner, ownerBStyle, ownerWidth, ownerColor); + info.rg->SetContinuousBCBorderWidth(NS_SIDE_BOTTOM, ownerWidth); + CalcDominantBorder(this, info.cg, nsnull, info.rg, info.bottomRow, + nsnull, PR_TRUE, NS_SIDE_BOTTOM, PR_TRUE, t2p, + owner, ownerBStyle, ownerWidth, ownerColor); + info.cg->SetContinuousBCBorderWidth(NS_SIDE_BOTTOM, ownerWidth); } else { PRInt32 segLength = 0; for (PRInt32 colX = info.colIndex; colX <= cellEndColIndex; colX += segLength) { iter.PeekBottom(info, colX, ajaInfo); const nsIFrame* rg = (info.rgBottom) ? info.rg : nsnull; - CalcDominantBorder(nsnull, nsnull, nsnull, rg, info.bottomRow, info.cell, PR_FALSE, NS_SIDE_BOTTOM, + CalcDominantBorder(nsnull, nsnull, nsnull, rg, info.bottomRow, info.cell, PR_FALSE, NS_SIDE_BOTTOM, PR_TRUE, t2p, owner, ownerBStyle, ownerWidth, ownerColor); rg = (ajaInfo.rgTop) ? ajaInfo.rg : nsnull; - CalcDominantBorder(nsnull, nsnull, nsnull, rg, ajaInfo.topRow, ajaInfo.cell, PR_FALSE, NS_SIDE_TOP, + CalcDominantBorder(nsnull, nsnull, nsnull, rg, ajaInfo.topRow, ajaInfo.cell, PR_FALSE, NS_SIDE_TOP, PR_FALSE, t2p, ajaOwner, ajaBStyle, ajaWidth, ajaColor); CalcDominantBorder(PR_FALSE, owner, ownerBStyle, ownerWidth, ownerColor, ajaOwner, ajaBStyle, ajaWidth, ajaColor, owner, ownerBStyle, ownerWidth, ownerColor, PR_TRUE); @@ -5972,23 +6067,23 @@ nsTableFrame::CalcBCBorders(nsIPresContext& aPresContext) } else if (prevRowIndex < cellEndRowIndex + 1) { // spans below the cell to the left topCorners[colX] = blCorner; - blCorner.Set(NS_SIDE_RIGHT, owner, ownerBStyle, ownerWidth, ownerColor); + blCorner.Set(NS_SIDE_RIGHT, owner, ownerBStyle, ownerWidth, ownerColor); update = PR_FALSE; } } if (update) { - blCorner.Update(NS_SIDE_RIGHT, owner, ownerBStyle, ownerWidth, ownerColor); + blCorner.Update(NS_SIDE_RIGHT, owner, ownerBStyle, ownerWidth, ownerColor); } if (BOTTOM_DAMAGED(cellEndRowIndex) && LEFT_DAMAGED(colX)) { if (hitsSpanBelow) { - tableCellMap->SetBCBorderCorner(eBottomLeft, *info.cellMap, iter.mRowGroupStart, cellEndRowIndex, colX, + tableCellMap->SetBCBorderCorner(eBottomLeft, *info.cellMap, iter.mRowGroupStart, cellEndRowIndex, colX, blCorner.ownerSide, blCorner.subWidth, blCorner.bevel); } // store any corners this cell spans together with the aja cell for (PRInt32 cX = colX + 1; cX < colX + segLength; cX++) { - BCCornerInfo& corner = bottomCorners[cX]; + BCCornerInfo& corner = bottomCorners[cX]; corner.Set(NS_SIDE_RIGHT, owner, ownerBStyle, ownerWidth, ownerColor); - tableCellMap->SetBCBorderCorner(eBottomLeft, *info.cellMap, iter.mRowGroupStart, cellEndRowIndex, + tableCellMap->SetBCBorderCorner(eBottomLeft, *info.cellMap, iter.mRowGroupStart, cellEndRowIndex, cX, corner.ownerSide, corner.subWidth, PR_FALSE); } } @@ -6008,7 +6103,7 @@ nsTableFrame::CalcBCBorders(nsIPresContext& aPresContext) // store the border segment the cell map and update cellBorders if (BOTTOM_DAMAGED(cellEndRowIndex) && LEFT_DAMAGED(colX) && RIGHT_DAMAGED(colX)) { - tableCellMap->SetBCBorderEdge(NS_SIDE_BOTTOM, *info.cellMap, iter.mRowGroupStart, cellEndRowIndex, + tableCellMap->SetBCBorderEdge(NS_SIDE_BOTTOM, *info.cellMap, iter.mRowGroupStart, cellEndRowIndex, colX, segLength, owner, ownerWidth, startSeg); // update the borders of the affected cells and rows DivideBCBorderSize(ownerWidth, smallHalf, largeHalf); @@ -6027,16 +6122,39 @@ nsTableFrame::CalcBCBorders(nsIPresContext& aPresContext) } // update bottom right corner BCCornerInfo& brCorner = bottomCorners[colX + segLength]; - brCorner.Update(NS_SIDE_LEFT, owner, ownerBStyle, ownerWidth, ownerColor); + brCorner.Update(NS_SIDE_LEFT, owner, ownerBStyle, ownerWidth, ownerColor); + } + if (!gotRowBorder && 1 == info.rowSpan) { + //get continuous row/row group border + //we need to check the row group's bottom border if this is + //the last row in the row group, but only a cell with rowspan=1 + //will know whether *this* row is at the bottom + const nsIFrame* rg = (info.rgBottom) ? info.rg : nsnull; + CalcDominantBorder(nsnull, nsnull, nsnull, rg, info.bottomRow, + nsnull, PR_FALSE, NS_SIDE_BOTTOM, PR_TRUE, t2p, + owner, ownerBStyle, ownerWidth, ownerColor); + rg = (ajaInfo.rgTop) ? ajaInfo.rg : nsnull; + CalcDominantBorder(nsnull, nsnull, nsnull, rg, ajaInfo.topRow, + nsnull, PR_FALSE, NS_SIDE_TOP, PR_FALSE, t2p, + ajaOwner, ajaBStyle, ajaWidth, ajaColor); + CalcDominantBorder(PR_FALSE, owner, ownerBStyle, ownerWidth, + ownerColor, ajaOwner, ajaBStyle, ajaWidth, + ajaColor, owner, ownerBStyle, ownerWidth, + ownerColor, PR_TRUE); + ajaInfo.topRow->SetContinuousBCBorderWidth(NS_SIDE_TOP, ownerWidth); + if (info.rgBottom) { + info.rg->SetContinuousBCBorderWidth(NS_SIDE_BOTTOM, ownerWidth); + } + gotRowBorder = PR_TRUE; } } // see if the cell to the right had a rowspan and its lower left border needs be joined with this one's bottom - if ((numCols != cellEndColIndex + 1) && // there is a cell to the right + if ((numCols != cellEndColIndex + 1) && // there is a cell to the right (lastBottomBorders[cellEndColIndex + 1].span > 1)) { // cell to right was a rowspan BCCornerInfo& corner = bottomCorners[cellEndColIndex + 1]; if ((NS_SIDE_TOP != corner.ownerSide) && (NS_SIDE_BOTTOM != corner.ownerSide)) { // not a vertical owner - BCCellBorder& thisBorder = lastBottomBorder; + BCCellBorder& thisBorder = lastBottomBorder; BCCellBorder& nextBorder = lastBottomBorders[info.colIndex + 1]; if ((thisBorder.color == nextBorder.color) && (thisBorder.width == nextBorder.width) && (thisBorder.style == nextBorder.style)) { @@ -7206,7 +7324,7 @@ PRBool nsTableFrame::RowHasSpanningCells(PRInt32 aRowIndex) nsTableCellMap* cellMap = GetCellMap(); NS_PRECONDITION (cellMap, "bad call, cellMap not yet allocated."); if (cellMap) { - result = cellMap->RowHasSpanningCells(aRowIndex); + result = cellMap->RowHasSpanningCells(aRowIndex); } return result; } @@ -7217,7 +7335,7 @@ PRBool nsTableFrame::RowIsSpannedInto(PRInt32 aRowIndex) nsTableCellMap* cellMap = GetCellMap(); NS_PRECONDITION (cellMap, "bad call, cellMap not yet allocated."); if (cellMap) { - result = cellMap->RowIsSpannedInto(aRowIndex); + result = cellMap->RowIsSpannedInto(aRowIndex); } return result; } diff --git a/mozilla/layout/html/table/src/nsTableFrame.h b/mozilla/layout/html/table/src/nsTableFrame.h index 0ffff8c1072..0a95bbe0916 100644 --- a/mozilla/layout/html/table/src/nsTableFrame.h +++ b/mozilla/layout/html/table/src/nsTableFrame.h @@ -62,10 +62,6 @@ struct nsStylePosition; enum nsPixelRound {eAlwaysRoundUp=0, eAlwaysRoundDown, eRoundUpIfHalfOrMore}; -// flags for Paint, PaintChild, PaintChildren are currently only used by tables. -// use low order bit of flags to distinguish between pass1(0) and pass2(1) border collapse backgrounds -#define BORDER_COLLAPSE_BACKGROUNDS 0x00000001 - #ifdef DEBUG_TABLE_REFLOW_TIMING #ifdef WIN32 #include @@ -331,6 +327,14 @@ public: // the surrounding margin space nsMargin GetBCMargin(nsIPresContext* aPresContext) const; + /** Get width of table + colgroup + col collapse: elements that + * continue along the length of the whole left side. + * see nsTablePainter about continuous borders + * @param aPixelsToTwips - conversion factor + * @param aGetInner - get only inner half of border width + */ + nscoord GetContinuousLeftBCBorderWidth(float aPixelsToTwips) const; + void SetBCDamageArea(nsIPresContext& aPresContext, const nsRect& aValue); @@ -643,7 +647,7 @@ protected: nsTableReflowState& aReflowState, nsReflowStatus& aStatus); - /** process a style chnaged notification. + /** process a style changed notification. * @see nsIFrameReflow::Reflow * TODO: needs to be optimized for which attribute was actually changed. */ @@ -797,11 +801,10 @@ public: nsVoidArray& GetColCache(); - /** - * Return aFrame's child if aFrame is an nsScrollFrame, otherwise return aFrame - */ - nsTableRowGroupFrame* GetRowGroupFrame(nsIFrame* aFrame, - nsIAtom* aFrameTypeIn = nsnull) const; + /** Return aFrame's child if aFrame is an nsScrollFrame, otherwise return aFrame + */ + static nsTableRowGroupFrame* GetRowGroupFrame(nsIFrame* aFrame, + nsIAtom* aFrameTypeIn = nsnull); protected: @@ -908,20 +911,21 @@ protected: // DATA MEMBERS struct TableBits { - unsigned mHadInitialReflow:1; // has intial reflow happened - unsigned mHaveReflowedColGroups:1; // have the col groups gotten their initial reflow - unsigned mNeedStrategyBalance:1; // does the strategy needs to balance the table - unsigned mNeedStrategyInit:1; // does the strategy needs to be initialized and then balance the table - unsigned mHasPctCol:1; // does any cell or col have a pct width - unsigned mCellSpansPctCol:1; // does any cell span a col with a pct width (or containing a cell with a pct width) - unsigned mDidResizeReflow:1; // did a resize reflow happen (indicating pass 2) - unsigned mIsBorderCollapse:1; // border collapsing model vs. separate model - unsigned mRowInserted:1; - unsigned mNeedSpecialReflow:1; - unsigned mNeedToInitiateSpecialReflow:1; - unsigned mInitiatedSpecialReflow:1; - unsigned mNeedToCalcBCBorders:1; - unsigned : 19; // unused + PRUint32 mHadInitialReflow:1; // has intial reflow happened + PRUint32 mHaveReflowedColGroups:1; // have the col groups gotten their initial reflow + PRUint32 mNeedStrategyBalance:1; // does the strategy needs to balance the table + PRUint32 mNeedStrategyInit:1; // does the strategy needs to be initialized and then balance the table + PRUint32 mHasPctCol:1; // does any cell or col have a pct width + PRUint32 mCellSpansPctCol:1; // does any cell span a col with a pct width (or containing a cell with a pct width) + PRUint32 mDidResizeReflow:1; // did a resize reflow happen (indicating pass 2) + PRUint32 mIsBorderCollapse:1; // border collapsing model vs. separate model + PRUint32 mRowInserted:1; + PRUint32 mNeedSpecialReflow:1; + PRUint32 mNeedToInitiateSpecialReflow:1; + PRUint32 mInitiatedSpecialReflow:1; + PRUint32 mNeedToCalcBCBorders:1; + PRUint32 mLeftContBCBorder:8; + PRUint32 : 11; // unused } mBits; nsTableCellMap* mCellMap; // maintains the relationships between rows, cols, and cells @@ -1041,7 +1045,7 @@ inline void nsTableFrame::SetRowInserted(PRBool aValue) inline nsFrameList& nsTableFrame::GetColGroups() { - return mColGroups; + return NS_STATIC_CAST(nsTableFrame*, GetFirstInFlow())->mColGroups; } inline nsVoidArray& nsTableFrame::GetColCache() @@ -1084,6 +1088,12 @@ inline void nsTableFrame::SetNeedToCalcBCBorders(PRBool aValue) mBits.mNeedToCalcBCBorders = (unsigned)aValue; } +inline nscoord +nsTableFrame::GetContinuousLeftBCBorderWidth(float aPixelsToTwips) const +{ + return BC_BORDER_RIGHT_HALF_COORD(aPixelsToTwips, mBits.mLeftContBCBorder); +} + enum nsTableIteration { eTableLTR = 0, eTableRTL = 1, diff --git a/mozilla/layout/html/table/src/nsTablePainter.cpp b/mozilla/layout/html/table/src/nsTablePainter.cpp new file mode 100644 index 00000000000..170a3cd916f --- /dev/null +++ b/mozilla/layout/html/table/src/nsTablePainter.cpp @@ -0,0 +1,685 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TableBackgroundPainter implementation. + * + * The Initial Developer of the Original Code is + * Elika J. Etemad ("fantasai") . + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsTableFrame.h" +#include "nsTableRowGroupFrame.h" +#include "nsTableRowFrame.h" +#include "nsTableColGroupFrame.h" +#include "nsTableColFrame.h" +#include "nsTableCellFrame.h" +#include "nsTablePainter.h" +#include "nsCSSRendering.h" + +/* ~*~ Standards Mode Painting ~*~ + + Background painting in Standards mode follows CSS2.1:17.5.1 + That section does not, however, describe the effect of + borders on background image positioning. What we do is: + + - in separate borders, the borders are passed in so that + their width figures in image positioning, even for rows/cols, which + don't have visible borders. This is done to allow authors + to position row backgrounds by, for example, aligning the + top left corner with the top left padding corner of the + top left table cell in the row in cases where all cells + have consistent border widths. If we didn't honor these + invisible borders, there would be no way to align + backgrounds with the padding edges, and designs would be + lost underneath the border. + + - in collapsing borders, because the borders collapse, we + use the -continuous border- width to synthesize a border + style and pass that in instead of using the element's + assigned style directly. + + The continuous border on a given edge of an element is + the collapse of all borders guaranteed to be continuous + along that edge. Cell borders are ignored (because, for + example, setting a thick border on the leftmost cell + should not shift the row background over; this way a + striped background set on will line up across rows + even if the cells are assigned arbitrary border widths. + + For example, the continous border on the top edge of a + row group is the collapse of any row group, row, and + table borders involved. (The first row group's top would + be [table-top + row group top + first row top]. It's bottom + would be [row group bottom + last row bottom + next row + top + next row group top].) + The top edge of a column group likewise includes the + table top, row group top, and first row top borders. However, + it *also* includes its own top border, since that is guaranteed + to be continuous. It does not include column borders because + those are not guaranteed to be continuous: there may be two + columns with different borders in a single column group. + + An alternative would be to define the continuous border as + [table? + row group + row] for horizontal + [table? + col group + col] for vertical + This makes it easier to line up backgrounds across elements + despite varying border widths, but it does not give much + flexibility in aligning /to/ those border widths. +*/ + +/* ~*~ Quirks Table Background Painting ~*~ + + Quirks inherits all backgrounds below the table level into the + cells; we don't paint intermediate backgrounds. +*/ + + +/* ~*~ TableBackgroundPainter ~*~ + + The TableBackgroundPainter is created and destroyed in one painting call. + Its principal function is PaintTable, which paints all table element + backgrounds. The initial code in that method sets up an array of column + data that caches the background styles and the border sizes for the + columns and colgroups in TableBackgroundData structs in mCols. Data for + BC borders are calculated and stashed in a synthesized border style struct + in the data struct since collapsed borders aren't the same width as style- + assigned borders. The data struct optimizes by only doing this if there's + an image background; otherwise we don't care. //XXX should also check background-origin + The class then loops through the row groups, rows, and cells. It uses + the mRowGroup and mRow TableBackgroundData structs to cache data for + the current frame in the loop. At the cell level, it paints the backgrounds, + one over the other, inside the cell rect. + + The exception to this pattern is when a table element has a view. + Elements with views are passed through, which means their data + (and their descendants' data) are not cached. The full loop is still + executed, however, so that underlying layers can get painted at the cell + level. + + The TableBackgroundPainter is then destroyed. + + Elements with views set up their own painter to finish the painting + process, since they were skipped. They call the appropriate sub-part + of the loop (e.g. PaintRow) which will paint the frame and descendants. + */ + +TableBackgroundPainter::TableBackgroundData::TableBackgroundData() + : mFrame(nsnull), + mBackground(nsnull), + mBorder(nsnull), + mSynthBorder(nsnull) +{ + MOZ_COUNT_CTOR(TableBackgroundData); +} + +TableBackgroundPainter::TableBackgroundData::~TableBackgroundData() +{ + NS_ASSERTION(!mSynthBorder, "must call Destroy before dtor"); + MOZ_COUNT_DTOR(TableBackgroundData); +} + +void +TableBackgroundPainter::TableBackgroundData::Destroy(nsIPresContext* aPresContext) +{ + NS_PRECONDITION(aPresContext, "null prescontext"); + if (mSynthBorder) { + mSynthBorder->Destroy(aPresContext); + mSynthBorder = nsnull; + } +} + +void +TableBackgroundPainter::TableBackgroundData::Clear() +{ + mRect.Empty(); + mFrame = nsnull; + mBorder = nsnull; + mBackground = nsnull; +} + +void +TableBackgroundPainter::TableBackgroundData::SetFrame(nsIFrame* aFrame) +{ + NS_PRECONDITION(aFrame, "null frame"); + mFrame = aFrame; + mRect = aFrame->GetRect(); +} + +void +TableBackgroundPainter::TableBackgroundData::SetFull(nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + nsIFrame* aFrame) +{ + NS_PRECONDITION(aFrame, "null frame"); + mFrame = aFrame; + mRect = aFrame->GetRect(); + /* IsVisibleForPainting doesn't use aRenderingContext except in nsTextFrames, + so we're not going to bother translating.*/ + PRBool isVisible; + nsresult rv = aFrame->IsVisibleForPainting(aPresContext, aRenderingContext, + PR_TRUE, &isVisible); + if (NS_SUCCEEDED(rv) && isVisible && + aFrame->GetStyleVisibility()->IsVisible()) { + mBackground = aFrame->GetStyleBackground(); + mBorder = aFrame->GetStyleBorder(); + } +} + +inline PRBool +TableBackgroundPainter::TableBackgroundData::ShouldSetBCBorder() +{ + /* we only need accurate border data when positioning background images*/ + return mBackground && !(mBackground->mBackgroundFlags & NS_STYLE_BG_IMAGE_NONE); +} + +nsresult +TableBackgroundPainter::TableBackgroundData::SetBCBorder(nsMargin& aBorder, + TableBackgroundPainter* aPainter) +{ + NS_PRECONDITION(aPainter, "null painter"); + if (!mSynthBorder) { + mSynthBorder = new (aPainter->mPresContext) + nsStyleBorder(aPainter->mZeroBorder); + if (!mSynthBorder) return NS_ERROR_OUT_OF_MEMORY; + } + + nsStyleCoord coord(aBorder.top); + mSynthBorder->mBorder.SetTop(coord); + coord.SetCoordValue(aBorder.right); + mSynthBorder->mBorder.SetRight(coord); + coord.SetCoordValue(aBorder.bottom); + mSynthBorder->mBorder.SetBottom(coord); + coord.SetCoordValue(aBorder.left); + mSynthBorder->mBorder.SetLeft(coord); + mSynthBorder->RecalcData(); + + mBorder = mSynthBorder; + return NS_OK; +} + +TableBackgroundPainter::TableBackgroundPainter(nsTableFrame* aTableFrame, + Origin aOrigin, + nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) + : mPresContext(aPresContext), + mRenderingContext(aRenderingContext), + mDirtyRect(aDirtyRect), + mOrigin(aOrigin), + mCols(nsnull), + mZeroBorder(aPresContext) +{ + MOZ_COUNT_CTOR(TableBackgroundPainter); + + mZeroBorder.SetBorderStyle(NS_SIDE_TOP, NS_STYLE_BORDER_STYLE_SOLID); + mZeroBorder.SetBorderStyle(NS_SIDE_RIGHT, NS_STYLE_BORDER_STYLE_SOLID); + mZeroBorder.SetBorderStyle(NS_SIDE_BOTTOM, NS_STYLE_BORDER_STYLE_SOLID); + mZeroBorder.SetBorderStyle(NS_SIDE_LEFT, NS_STYLE_BORDER_STYLE_SOLID); + nsStyleCoord coord(0); + mZeroBorder.mBorder.SetTop(coord); + mZeroBorder.mBorder.SetRight(coord); + mZeroBorder.mBorder.SetBottom(coord); + mZeroBorder.mBorder.SetLeft(coord); + mZeroBorder.RecalcData(); + + mZeroPadding.RecalcData(); + + mPresContext->GetScaledPixelsToTwips(&mP2t); + mIsBorderCollapse = aTableFrame->IsBorderCollapse(); +#ifdef DEBUG + mCompatMode = mPresContext->CompatibilityMode(); +#endif + mNumCols = aTableFrame->GetColCount(); +} + +TableBackgroundPainter::~TableBackgroundPainter() +{ + if (mCols) { + TableBackgroundData* lastColGroup = nsnull; + for (PRUint32 i = 0; i < mNumCols; i++) { + if (mCols[i].mColGroup != lastColGroup) { + lastColGroup = mCols[i].mColGroup; + lastColGroup->Destroy(mPresContext); + delete lastColGroup; + } + mCols[i].mColGroup = nsnull; + mCols[i].mCol.Destroy(mPresContext); + } + delete [] mCols; + } + mRowGroup.Destroy(mPresContext); + mRow.Destroy(mPresContext); + MOZ_COUNT_DTOR(TableBackgroundPainter); +} + +nsresult +TableBackgroundPainter::PaintTableFrame(nsTableFrame* aTableFrame, + nsTableRowGroupFrame* aFirstRowGroup, + nsTableRowGroupFrame* aLastRowGroup, + nsMargin* aDeflate) +{ + NS_PRECONDITION(aTableFrame, "null frame"); + TableBackgroundData tableData; + tableData.SetFull(mPresContext, mRenderingContext, aTableFrame); + tableData.mRect.MoveTo(0,0); //using table's coords + if (aDeflate) { + 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(mP2t, tempBorder); + } + border.right = tempBorder.right; + + aLastRowGroup->GetContinuousBCBorderWidth(mP2t, tempBorder); + border.bottom = tempBorder.bottom; + + nsTableRowFrame* rowFrame = aFirstRowGroup->GetFirstRow(); + if (rowFrame) { + rowFrame->GetContinuousBCBorderWidth(mP2t, tempBorder); + border.top = tempBorder.top; + } + + border.left = aTableFrame->GetContinuousLeftBCBorderWidth(mP2t); + + 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, + *tableData.mBackground, + *tableData.mBorder, + mZeroPadding, PR_TRUE); + } + tableData.Destroy(mPresContext); + return NS_OK; +} + +void +TableBackgroundPainter::TranslateContext(nscoord aDX, + nscoord aDY) +{ + mRenderingContext.Translate(aDX, aDY); + mDirtyRect.MoveBy(-aDX, -aDY); + if (mCols) { + TableBackgroundData* lastColGroup = nsnull; + for (PRUint32 i = 0; i < mNumCols; i++) { + mCols[i].mCol.mRect.MoveBy(-aDX, -aDY); + if (lastColGroup != mCols[i].mColGroup) { + NS_ASSERTION(mCols[i].mColGroup, "colgroup data should not be null"); + mCols[i].mColGroup->mRect.MoveBy(-aDX, -aDY); + lastColGroup = mCols[i].mColGroup; + } + } + } +} + +nsresult +TableBackgroundPainter::QuirksPaintTable(nsTableFrame* aTableFrame, + nsMargin& aDeflate) +{ + NS_PRECONDITION(aTableFrame, "null table frame"); + NS_PRECONDITION(eCompatibility_NavQuirks == mCompatMode, + "QuirksPaintTable called for non-Quirks"); + + nsVoidArray rowGroups; + PRUint32 numRowGroups; + aTableFrame->OrderRowGroups(rowGroups, numRowGroups); + + if (numRowGroups < 1) { //degenerate case + PaintTableFrame(aTableFrame,nsnull, nsnull, &aDeflate); + /* No cells; nothing else to paint */ + return NS_OK; + } + + PaintTableFrame(aTableFrame, + aTableFrame->GetRowGroupFrame(NS_STATIC_CAST(nsIFrame*, rowGroups.ElementAt(0))), + aTableFrame->GetRowGroupFrame(NS_STATIC_CAST(nsIFrame*, rowGroups.ElementAt(numRowGroups - 1))), + &aDeflate); + + if (mIsBorderCollapse) { + /* This is a simple pass, so we'll just keep with the table coord system. */ + + for (PRUint32 i = 0; i < numRowGroups; i++) { + nsTableRowGroupFrame* rg = aTableFrame->GetRowGroupFrame(NS_STATIC_CAST(nsIFrame*, rowGroups.ElementAt(i))); + nsRect rgRect = rg->GetRect(); + if (rgRect.Intersects(mDirtyRect) && !rg->HasView()) { + for (nsTableRowFrame* row = rg->GetFirstRow(); row; row = row->GetNextRow()) { + nsRect rowRect = row->GetRect(); + rowRect.MoveBy(rgRect.x, rgRect.y); + if (mDirtyRect.YMost() > rowRect.y && //Intersect won't handle rowspans + !row->HasView()) { + for (nsTableCellFrame* cell = row->GetFirstCell(); cell; cell = cell->GetNextCell()) { + mCellRect = cell->GetRect(); + mCellRect.MoveBy(rowRect.x, rowRect.y); + if (mCellRect.Intersects(mDirtyRect) && !cell->HasView()) { + nsresult rv = PaintCell(cell, PR_FALSE); + if (NS_FAILED(rv)) return rv; + } + } + } + } + } + } + } + return NS_OK; +} + +nsresult +TableBackgroundPainter::PaintTable(nsTableFrame* aTableFrame) +{ + NS_PRECONDITION(aTableFrame, "null table frame"); + NS_PRECONDITION(eCompatibility_NavQuirks != mCompatMode, + "must call QuirksPaintTable in Quirks mode, not PaintTable"); + + nsVoidArray rowGroups; + PRUint32 numRowGroups; + aTableFrame->OrderRowGroups(rowGroups, numRowGroups); + + if (numRowGroups < 1) { //degenerate case + PaintTableFrame(aTableFrame,nsnull, nsnull, nsnull); + /* No cells; nothing else to paint */ + return NS_OK; + } + + PaintTableFrame(aTableFrame, + aTableFrame->GetRowGroupFrame(NS_STATIC_CAST(nsIFrame*, rowGroups.ElementAt(0))), + aTableFrame->GetRowGroupFrame(NS_STATIC_CAST(nsIFrame*, rowGroups.ElementAt(numRowGroups - 1))), + nsnull); + + /*Set up column background/border data*/ + if (mNumCols > 0) { + nsFrameList& colGroupList = aTableFrame->GetColGroups(); + NS_ASSERTION(colGroupList.FirstChild(), "table should have at least one colgroup"); + + mCols = new ColData[mNumCols]; + if (!mCols) return NS_ERROR_OUT_OF_MEMORY; + + TableBackgroundData* cgData = nsnull; + nsMargin border; + /* BC left borders aren't stored on cols, but the previous column's + right border is the next one's left border.*/ + //Start with table's left border. + nscoord lastLeftBorder = aTableFrame->GetContinuousLeftBCBorderWidth(mP2t); + for (nsTableColGroupFrame* cgFrame = NS_STATIC_CAST(nsTableColGroupFrame*, colGroupList.FirstChild()); + cgFrame; cgFrame = NS_STATIC_CAST(nsTableColGroupFrame*, cgFrame->GetNextSibling())) { + + if (cgFrame->GetColCount() < 1) { + //No columns, no cells, so no need for data + continue; + } + + /*Create data struct for column group*/ + cgData = new TableBackgroundData; + if (!cgData) return NS_ERROR_OUT_OF_MEMORY; + cgData->SetFull(mPresContext, mRenderingContext, cgFrame); + if (mIsBorderCollapse && cgData->ShouldSetBCBorder()) { + border.left = lastLeftBorder; + cgFrame->GetContinuousBCBorderWidth(mP2t, border); + nsresult rv = cgData->SetBCBorder(border, this); + if (NS_FAILED(rv)) { + cgData->Destroy(mPresContext); + delete cgData; + return rv; + } + } + + /*Loop over columns in this colgroup*/ + if (cgData->IsVisible()) { + for (nsTableColFrame* col = cgFrame->GetFirstColumn(); col; + col = NS_STATIC_CAST(nsTableColFrame*, col->GetNextSibling())) { + /*Create data struct for column*/ + PRUint32 colIndex = col->GetColIndex(); + mCols[colIndex].mCol.SetFull(mPresContext, mRenderingContext, col); + //Bring column mRect into table's coord system + mCols[colIndex].mCol.mRect.MoveBy(cgData->mRect.x, cgData->mRect.y); + //link to parent colgroup's data + mCols[colIndex].mColGroup = cgData; + if (mIsBorderCollapse) { + border.left = lastLeftBorder; + lastLeftBorder = col->GetContinuousBCBorderWidth(mP2t, border); + if (mCols[colIndex].mCol.ShouldSetBCBorder()) { + nsresult rv = mCols[colIndex].mCol.SetBCBorder(border, this); + if (NS_FAILED(rv)) return rv; + } + mCols[colIndex].mCol.mBorder->GetBorder(border); + } + } + } + } + } + + for (PRUint32 i = 0; i < numRowGroups; i++) { + nsTableRowGroupFrame* rg = nsTableFrame::GetRowGroupFrame(NS_STATIC_CAST(nsIFrame*, rowGroups.ElementAt(i))); + nsRect rgRect = rg->GetRect(); + if (rgRect.Intersects(mDirtyRect)) { + nsresult rv = PaintRowGroup(rg, rg->HasView()); + if (NS_FAILED(rv)) return rv; + } + } + return NS_OK; +} + +nsresult +TableBackgroundPainter::PaintRowGroup(nsTableRowGroupFrame* aFrame, + PRBool aPassThrough) +{ + NS_PRECONDITION(aFrame, "null frame"); + NS_PRECONDITION(eCompatibility_NavQuirks != mCompatMode, + "must not call PaintRowGroup in Quirks mode"); + + nsTableRowFrame* firstRow = aFrame->GetFirstRow(); + + /* Load row group data */ + if (!aPassThrough) { + mRowGroup.SetFull(mPresContext, mRenderingContext, aFrame); + if (mIsBorderCollapse && mRowGroup.ShouldSetBCBorder()) { + nsMargin border; + if (firstRow) { + //pick up first row's top border (= rg top border) + firstRow->GetContinuousBCBorderWidth(mP2t, border); + /* (row group doesn't store its top border) */ + } + //overwrite sides+bottom borders with rg's own + aFrame->GetContinuousBCBorderWidth(mP2t, border); + nsresult res = mRowGroup.SetBCBorder(border, this); + if (!NS_SUCCEEDED(res)) { + return res; + } + } + aPassThrough = !mRowGroup.IsVisible(); + } + else { + mRowGroup.SetFrame(aFrame); + } + + /* translate everything into row group coord system*/ + if (eOrigin_TableRowGroup != mOrigin) { + TranslateContext(mRowGroup.mRect.x, mRowGroup.mRect.y); + } + nsRect rgRect = mRowGroup.mRect; + mRowGroup.mRect.MoveTo(0, 0); + + /* paint */ + for (nsTableRowFrame* row = firstRow; row; row = row->GetNextRow()) { + nsRect rect = row->GetRect(); + if (mDirtyRect.YMost() >= rect.y) { //Intersect wouldn't handle rowspans + nsresult rv = PaintRow(row, aPassThrough || row->HasView()); + if (NS_FAILED(rv)) return rv; + } + } + + /* translate back into table coord system */ + if (eOrigin_TableRowGroup != mOrigin) { + TranslateContext(-rgRect.x, -rgRect.y); + } + + /* unload rg data */ + mRowGroup.Clear(); + + return NS_OK; +} + +nsresult +TableBackgroundPainter::PaintRow(nsTableRowFrame* aFrame, + PRBool aPassThrough) +{ + NS_PRECONDITION(aFrame, "null frame"); + NS_PRECONDITION(eCompatibility_NavQuirks != mCompatMode, + "must not call PaintRow in Quirks mode"); + /* Load row data */ + if (!aPassThrough) { + mRow.SetFull(mPresContext, mRenderingContext, aFrame); + if (mIsBorderCollapse && mRow.ShouldSetBCBorder()) { + nsMargin border; + nsTableRowFrame* nextRow = aFrame->GetNextRow(); + if (nextRow) { //outer top below us is inner bottom for us + border.bottom = nextRow->GetOuterTopContBCBorderWidth(mP2t); + } + else { //acquire rg's bottom border + nsTableRowGroupFrame* rowGroup = NS_STATIC_CAST(nsTableRowGroupFrame*, aFrame->GetParent()); + rowGroup->GetContinuousBCBorderWidth(mP2t, border); + } + //get the rest of the borders; will overwrite all but bottom + aFrame->GetContinuousBCBorderWidth(mP2t, border); + + nsresult res = mRow.SetBCBorder(border, this); + if (!NS_SUCCEEDED(res)) { + return res; + } + } + aPassThrough = !mRow.IsVisible(); + } + else { + mRow.SetFrame(aFrame); + } + + /* Translate */ + if (eOrigin_TableRow == mOrigin) { + /* If we originate from the row, then make the row the origin. */ + mRow.mRect.MoveTo(0, 0); + } + //else: Use row group's coord system -> no translation necessary + + for (nsTableCellFrame* cell = aFrame->GetFirstCell(); cell; cell = cell->GetNextCell()) { + mCellRect = cell->GetRect(); + //Translate to use the same coord system as mRow. + mCellRect.MoveBy(mRow.mRect.x, mRow.mRect.y); + if (mCellRect.Intersects(mDirtyRect)) { + nsresult rv = PaintCell(cell, aPassThrough || cell->HasView()); + if (NS_FAILED(rv)) return rv; + } + } + + /* Unload row data */ + mRow.Clear(); + return NS_OK; +} + +nsresult +TableBackgroundPainter::PaintCell(nsTableCellFrame* aCell, + PRBool aPassSelf) +{ + NS_PRECONDITION(aCell, "null frame"); + + const nsStyleTableBorder* cellTableStyle; + cellTableStyle = aCell->GetStyleTableBorder(); + if (!(NS_STYLE_TABLE_EMPTY_CELLS_SHOW == cellTableStyle->mEmptyCells || + NS_STYLE_TABLE_EMPTY_CELLS_SHOW_BACKGROUND == cellTableStyle->mEmptyCells) + && aCell->GetContentEmpty()) { + return NS_OK; + } + + PRInt32 colIndex; + aCell->GetColIndex(colIndex); + + //Paint column group background + if (mCols && mCols[colIndex].mColGroup && mCols[colIndex].mColGroup->IsVisible()) { + nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext, + mCols[colIndex].mColGroup->mFrame, mDirtyRect, + mCols[colIndex].mColGroup->mRect, + *mCols[colIndex].mColGroup->mBackground, + *mCols[colIndex].mColGroup->mBorder, + mZeroPadding, PR_TRUE, &mCellRect); + } + + //Paint column background + if (mCols && mCols[colIndex].mCol.IsVisible()) { + nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext, + mCols[colIndex].mCol.mFrame, mDirtyRect, + mCols[colIndex].mCol.mRect, + *mCols[colIndex].mCol.mBackground, + *mCols[colIndex].mCol.mBorder, + mZeroPadding, PR_TRUE, &mCellRect); + } + + //Paint row group background + if (mRowGroup.IsVisible()) { + nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext, + mRowGroup.mFrame, mDirtyRect, mRowGroup.mRect, + *mRowGroup.mBackground, *mRowGroup.mBorder, + mZeroPadding, PR_TRUE, &mCellRect); + } + + //Paint row background + if (mRow.IsVisible()) { + nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext, + mRow.mFrame, mDirtyRect, mRow.mRect, + *mRow.mBackground, *mRow.mBorder, + mZeroPadding, PR_TRUE, &mCellRect); + } + + //Paint cell background in border-collapse unless we're just passing + if (mIsBorderCollapse && !aPassSelf) { + mRenderingContext.PushState(); + mRenderingContext.Translate(mCellRect.x, mCellRect.y); + mDirtyRect.MoveBy(-mCellRect.x, -mCellRect.y); + aCell->Paint(mPresContext, mRenderingContext, mDirtyRect, + NS_FRAME_PAINT_LAYER_BACKGROUND, + NS_PAINT_FLAG_TABLE_BG_PAINT | NS_PAINT_FLAG_TABLE_CELL_BG_PASS); + mDirtyRect.MoveBy(mCellRect.x, mCellRect.y); + PRBool clipEmpty; + mRenderingContext.PopState(clipEmpty); + } + + return NS_OK; +} diff --git a/mozilla/layout/html/table/src/nsTablePainter.h b/mozilla/layout/html/table/src/nsTablePainter.h new file mode 100644 index 00000000000..285694b1bb6 --- /dev/null +++ b/mozilla/layout/html/table/src/nsTablePainter.h @@ -0,0 +1,271 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TableBackgroundPainter interface. + * + * The Initial Developer of the Original Code is + * Elika J. Etemad ("fantasai") . + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsTablePainter_h__ +#define nsTablePainter_h__ + +typedef PRUint8 BCPixelSize; + +#define BC_BORDER_TOP_HALF_COORD(p2t,px) NSToCoordRound(((px) - (px) / 2) * (p2t) ) +#define BC_BORDER_RIGHT_HALF_COORD(p2t,px) NSToCoordRound(( (px) / 2) * (p2t) ) +#define BC_BORDER_BOTTOM_HALF_COORD(p2t,px) NSToCoordRound(( (px) / 2) * (p2t) ) +#define BC_BORDER_LEFT_HALF_COORD(p2t,px) NSToCoordRound(((px) - (px) / 2) * (p2t) ) + +#define BC_BORDER_TOP_HALF(px) ((px) - (px) / 2) +#define BC_BORDER_RIGHT_HALF(px) ((px) / 2) +#define BC_BORDER_BOTTOM_HALF(px) ((px) / 2) +#define BC_BORDER_LEFT_HALF(px) ((px) - (px) / 2) + +// flags for Paint, PaintChild, PaintChildren are currently only used by tables. +//Table-based paint call; not a direct call as with views +#define NS_PAINT_FLAG_TABLE_BG_PAINT 0x00000001 +//Cells should paint their backgrounds only, no children +#define NS_PAINT_FLAG_TABLE_CELL_BG_PASS 0x00000002 + +#include "nsIFrame.h" +class nsTableFrame; +class nsTableRowGroupFrame; +class nsTableRowFrame; +class nsTableCellFrame; + +class TableBackgroundPainter +{ + /* + * Helper class for painting table backgrounds + * + */ + + public: + + enum Origin { eOrigin_Table, eOrigin_TableRowGroup, eOrigin_TableRow }; + + /** Public constructor + * @param aTableFrame - the table's table frame + * @param aOrigin - what type of table frame is creating this instance + * @param aPresContext - the presentation context + * @param aRenderingContext - the rendering context + * @param aDirtyRect - the area that needs to be painted + */ + TableBackgroundPainter(nsTableFrame* aTableFrame, + Origin aOrigin, + nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + + /** Destructor */ + ~TableBackgroundPainter(); + + /* ~*~ The Border Collapse Painting Issue ~*~ + + In border-collapse, the *table* paints the cells' borders, + so we need to make sure the backgrounds get painted first + (underneath) by doing a cell-background-only painting pass. + This happens in both Standards and Quirks mode PaintTable + calls. + The table must then do a no-cell-background pass that + continues as a normal background paint call in the cell + descendants.) This method doesn't handle views very well, but + then, nothing about BC table painting really does. + */ + + /* ~*~ Using Standards Mode Painting ~*~ + + A call to PaintTable will normally paint all of the table's + elements (except the cells in non-BC). Elements with views + however, will be skipped and must create their own painter + to call the appropriate paint function in their ::Paint + method (e.g. painter.PaintRow in nsTableRow::Paint) + */ + + /** Paint background for the table frame and its children down through cells + * (Cells themselves will only be painted in border collapse) + * Standards mode only + * Table must do a flagged TABLE_BG_PAINT ::Paint call on its + * children afterwards + * @param aTableFrame - the table frame + */ + nsresult PaintTable(nsTableFrame* aTableFrame); + + /** Paint background for the row group and its children down through cells + * (Cells themselves will only be painted in border collapse) + * Standards mode only + * Table Row Group must do a flagged TABLE_BG_PAINT ::Paint call on its + * children afterwards + * @param aFrame - the table row group frame + */ + nsresult PaintRowGroup(nsTableRowGroupFrame* aFrame) + { return PaintRowGroup(aFrame, PR_FALSE); } + + /** Paint background for the row and its children down through cells + * (Cells themselves will only be painted in border collapse) + * Standards mode only + * Table Row must do a flagged TABLE_BG_PAINT ::Paint call on its + * children afterwards + * @param aFrame - the table row frame + */ + nsresult PaintRow(nsTableRowFrame* aFrame) + { return PaintRow(aFrame, PR_FALSE); } + + + /** Paint table's background, Quirks mode only + * Cell backgrounds will also be painted in border collapse: + * Table must do a flagged TABLE_BG_PAINT on its children + * afterwards. + * @param aTableFrame - the table frame + * @param aDeflate - deflation needed to bring table's mRect + * to the outer grid lines in border-collapse + */ + nsresult QuirksPaintTable(nsTableFrame* aTableFrame, + nsMargin& aDeflate); + + private: + + /** Paint table frame's background + * @param aTableFrame - the table frame + * @param aFirstRowGroup - the first (in layout order) row group + * may be null + * @param aLastRowGroup - the last (in layout order) row group + * may be null + * @param aDeflate - adjustment to frame's rect (used for quirks BC) + * may be null + */ + nsresult PaintTableFrame(nsTableFrame* aTableFrame, + nsTableRowGroupFrame* aFirstRowGroup, + nsTableRowGroupFrame* aLastRowGroup, + nsMargin* aDeflate = nsnull); + + /* aPassThrough params indicate whether to paint the element or to just + * pass through and paint underlying layers only + * See Public versions for function descriptions + */ + nsresult PaintRowGroup(nsTableRowGroupFrame* aFrame, + PRBool aPassThrough); + nsresult PaintRow(nsTableRowFrame* aFrame, + PRBool aPassThrough); + + /** Paint table background layers for this cell space + * Also paints cell's own background in border-collapse mode + * @param aFrame - the cell + * @param aPassSelf - pass this cell; i.e. paint only underlying layers + */ + nsresult PaintCell(nsTableCellFrame* aFrame, + PRBool aPassSelf); + + /** Translate mRenderingContext, mDirtyRect, and mCols' column and + * colgroup coords + * @param aDX - origin's x-coord change + * @param aDY - origin's y-coord change + */ + void TranslateContext(nscoord aDX, + nscoord aDY); + + struct TableBackgroundData; + friend struct TableBackgroundData; + MOZ_DECL_CTOR_COUNTER(TableBackgroundData) + struct TableBackgroundData { + nsIFrame* mFrame; + nsRect mRect; + const nsStyleBackground* mBackground; + const nsStyleBorder* mBorder; + + /** Data is valid & frame is visible */ + PRBool IsVisible() const { return mBackground != nsnull; } + + /** Constructor */ + TableBackgroundData(); + /** Destructor */ + ~TableBackgroundData(); + /** Destroys synthesized data. MUST be called before destructor + * @param aPresContext - the pres context + */ + void Destroy(nsIPresContext* aPresContext); + + + /** Clear background data */ + void Clear(); + + /** Calculate and set all data values to represent aFrame */ + void SetFull(nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + nsIFrame* aFrame); + + /** Set frame data (mFrame, mRect) but leave style data empty */ + void SetFrame(nsIFrame* aFrame); + + /** True if need to set border-collapse border; must call SetFull beforehand */ + PRBool ShouldSetBCBorder(); + + /** Set border-collapse border with aBorderWidth as widths */ + nsresult SetBCBorder(nsMargin& aBorderWidth, + TableBackgroundPainter* aPainter); + + private: + nsStyleBorder* mSynthBorder; + }; + + struct ColData { + TableBackgroundData mCol; + TableBackgroundData* mColGroup; //link to col's parent colgroup's data (owned by painter) + ColData() { + mColGroup = nsnull; + } + }; + + nsIPresContext* mPresContext; + nsIRenderingContext& mRenderingContext; + nsRect mDirtyRect; +#ifdef DEBUG + nsCompatibility mCompatMode; +#endif + PRBool mIsBorderCollapse; + Origin mOrigin; //user's table frame type + + ColData* mCols; //array of columns' ColData + PRUint32 mNumCols; + TableBackgroundData mRowGroup; //current row group + TableBackgroundData mRow; //current row + nsRect mCellRect; //current cell's rect + + + nsStyleBorder mZeroBorder; //cached zero-width border + nsStylePadding mZeroPadding; //cached zero-width padding + float mP2t; //pixels to twips + +}; +MOZ_DECL_CTOR_COUNTER(TableBackgroundPainter) + +#endif diff --git a/mozilla/layout/html/table/src/nsTableRowFrame.cpp b/mozilla/layout/html/table/src/nsTableRowFrame.cpp index 1670119d6c8..8a007e50c66 100644 --- a/mozilla/layout/html/table/src/nsTableRowFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableRowFrame.cpp @@ -538,7 +538,25 @@ NS_METHOD nsTableRowFrame::Paint(nsIPresContext* aPresContext, aRenderingContext.DrawRect(0, 0, mRect.width, mRect.height); } #endif - // Standards mode background painting removed. See bug 4510 + + if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer && + //direct (not table-called) background paint + !(aFlags & (NS_PAINT_FLAG_TABLE_BG_PAINT | NS_PAINT_FLAG_TABLE_CELL_BG_PASS))) { + //Quirks inherits bg into cells & paints them there + if (eCompatibility_NavQuirks != aPresContext->CompatibilityMode()) { + nsTableFrame* tableFrame; + nsTableFrame::GetTableFrame(this, tableFrame); + NS_ASSERTION(tableFrame, "null table frame"); + + TableBackgroundPainter painter(tableFrame, + TableBackgroundPainter::eOrigin_TableRow, + aPresContext, aRenderingContext, + aDirtyRect); + nsresult rv = painter.PaintRow(this); + if (NS_FAILED(rv)) return rv; + aFlags |= NS_PAINT_FLAG_TABLE_BG_PAINT; + } + } PRUint8 overflow = GetStyleDisplay()->mOverflow; PRBool clip = overflow == NS_STYLE_OVERFLOW_HIDDEN || @@ -547,7 +565,8 @@ NS_METHOD nsTableRowFrame::Paint(nsIPresContext* aPresContext, aRenderingContext.PushState(); SetOverflowClipRect(aRenderingContext); } - PaintChildren(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer, aFlags); + PaintChildren(aPresContext, aRenderingContext, aDirtyRect, + aWhichLayer, aFlags); if (clip) { PRBool clipState; aRenderingContext.PopState(clipState); @@ -862,8 +881,7 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext, PRInt32 cellColIndex; cellFrame->GetColIndex(cellColIndex); cellColSpan = aTableFrame.GetEffectiveColSpan(*cellFrame); - - x += cellSpacingX; + // If the adjacent cell is in a prior row (because of a rowspan) add in the space if ((iter.IsLeftToRight() && (prevColIndex != (cellColIndex - 1))) || (!iter.IsLeftToRight() && (prevColIndex != cellColIndex + cellColSpan))) { @@ -1034,10 +1052,7 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext, } ConsiderChildOverflow(aPresContext, aDesiredSize.mOverflowArea, kidFrame); kidFrame = iter.Next(); // Get the next child - // if this was the last child, and it had a colspan>1, add in the cellSpacing for the colspan - // if the last kid wasn't a colspan, then we still have the colspan of the last real cell - if (!kidFrame && (cellColSpan > 1)) - x += cellSpacingX; + x += cellSpacingX; } // just set our width to what was available. The table will calculate the width and not use our value. @@ -1524,6 +1539,24 @@ nsTableRowFrame::GetUnpaginatedHeight(nsIPresContext* aPresContext) return 0; } +void nsTableRowFrame::SetContinuousBCBorderWidth(PRUint8 aForSide, + BCPixelSize aPixelValue) +{ + switch (aForSide) { + case NS_SIDE_RIGHT: + mRightContBorderWidth = aPixelValue; + return; + case NS_SIDE_TOP: + mTopContBorderWidth = aPixelValue; + return; + case NS_SIDE_LEFT: + mLeftContBorderWidth = aPixelValue; + return; + default: + NS_ERROR("invalid NS_SIDE arg"); + } +} + /* ----- global methods ----- */ nsresult diff --git a/mozilla/layout/html/table/src/nsTableRowFrame.h b/mozilla/layout/html/table/src/nsTableRowFrame.h index 483daabba18..b1ad3aa723f 100644 --- a/mozilla/layout/html/table/src/nsTableRowFrame.h +++ b/mozilla/layout/html/table/src/nsTableRowFrame.h @@ -39,6 +39,7 @@ #include "nscore.h" #include "nsHTMLContainerFrame.h" +#include "nsTablePainter.h" class nsTableFrame; class nsTableCellFrame; @@ -226,11 +227,31 @@ public: void SetUnpaginatedHeight(nsIPresContext* aPresContext, nscoord aValue); nscoord GetTopBCBorderWidth(float* aPixelsToTwips = nsnull); - void SetTopBCBorderWidth(nscoord aWidth); + void SetTopBCBorderWidth(BCPixelSize aWidth); nscoord GetBottomBCBorderWidth(float* aPixelsToTwips = nsnull); - void SetBottomBCBorderWidth(nscoord aWidth); + void SetBottomBCBorderWidth(BCPixelSize aWidth); nsMargin* GetBCBorderWidth(float aPixelsToTwips, nsMargin& aBorder); + + /** + * Gets inner border widths before collapsing with cell borders + * Caller must get bottom border from next row or from table + * GetContinuousBCBorderWidth will not overwrite aBorder.bottom + * see nsTablePainter about continuous borders + */ + void GetContinuousBCBorderWidth(float aPixelsToTwips, + nsMargin& aBorder); + /** + * @returns outer top bc border == prev row's bottom inner + */ + nscoord GetOuterTopContBCBorderWidth(float aPixelsToTwips); + /** + * Sets full border widths before collapsing with cell borders + * @param aForSide - side to set; only accepts right, left, and top + */ + void SetContinuousBCBorderWidth(PRUint8 aForSide, + BCPixelSize aPixelValue); + protected: /** protected constructor. @@ -238,7 +259,7 @@ protected: */ nsTableRowFrame(); - void InitChildReflowState(nsIPresContext& aPresContext, + void InitChildReflowState(nsIPresContext& aPresContext, const nsSize& aAvailSize, PRBool aBorderCollapse, float aPixelsToTwips, @@ -318,8 +339,11 @@ private: nscoord mMaxCellDescent; // does *not* include cells with rowspan > 1 // border widths in pixels in the collapsing border model - unsigned mTopBorderWidth:8; - unsigned mBottomBorderWidth:8; + BCPixelSize mTopBorderWidth; + BCPixelSize mBottomBorderWidth; + BCPixelSize mRightContBorderWidth; + BCPixelSize mTopContBorderWidth; + BCPixelSize mLeftContBorderWidth; #ifdef DEBUG_TABLE_REFLOW_TIMING public: @@ -433,7 +457,7 @@ inline nscoord nsTableRowFrame::GetTopBCBorderWidth(float* aPixelsToTwips) return width; } -inline void nsTableRowFrame::SetTopBCBorderWidth(nscoord aWidth) +inline void nsTableRowFrame::SetTopBCBorderWidth(BCPixelSize aWidth) { mTopBorderWidth = aWidth; } @@ -444,7 +468,7 @@ inline nscoord nsTableRowFrame::GetBottomBCBorderWidth(float* aPixelsToTwips) return width; } -inline void nsTableRowFrame::SetBottomBCBorderWidth(nscoord aWidth) +inline void nsTableRowFrame::SetBottomBCBorderWidth(BCPixelSize aWidth) { mBottomBorderWidth = aWidth; } @@ -460,4 +484,21 @@ inline nsMargin* nsTableRowFrame::GetBCBorderWidth(float aPixelsToTwips, return &aBorder; } +inline void +nsTableRowFrame::GetContinuousBCBorderWidth(float aPixelsToTwips, + nsMargin& aBorder) +{ + aBorder.right = BC_BORDER_LEFT_HALF_COORD(aPixelsToTwips, + mLeftContBorderWidth); + aBorder.top = BC_BORDER_BOTTOM_HALF_COORD(aPixelsToTwips, + mTopContBorderWidth); + aBorder.left = BC_BORDER_RIGHT_HALF_COORD(aPixelsToTwips, + mRightContBorderWidth); +} + +inline nscoord nsTableRowFrame::GetOuterTopContBCBorderWidth(float aPixelsToTwips) +{ + return BC_BORDER_TOP_HALF_COORD(aPixelsToTwips, mTopContBorderWidth); +} + #endif diff --git a/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp b/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp index 380dd48c24c..bfbba9e24e7 100644 --- a/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp @@ -94,7 +94,7 @@ nsTableRowGroupFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) *aInstancePtr = (void*)this; return NS_OK; } - else if (aIID.Equals(NS_GET_IID(nsILineIteratorNavigator))) + else if (aIID.Equals(NS_GET_IID(nsILineIteratorNavigator))) { // note there is no addref here, frames are not addref'd *aInstancePtr = (void*)(nsILineIteratorNavigator*)this; return NS_OK; @@ -204,7 +204,25 @@ NS_METHOD nsTableRowGroupFrame::Paint(nsIPresContext* aPresContext, aRenderingContext.DrawRect(0, 0, mRect.width, mRect.height); } #endif - // Standards mode background painting removed. See bug 4510 + + if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer && + //direct (not table-called) background paint + !(aFlags & (NS_PAINT_FLAG_TABLE_BG_PAINT | NS_PAINT_FLAG_TABLE_CELL_BG_PASS))) { + //Quirks inherits bg into cells & paints them there + if (eCompatibility_NavQuirks != aPresContext->CompatibilityMode()) { + nsTableFrame* tableFrame; + nsTableFrame::GetTableFrame(this, tableFrame); + NS_ASSERTION(tableFrame, "null table frame"); + + TableBackgroundPainter painter(tableFrame, + TableBackgroundPainter::eOrigin_TableRowGroup, + aPresContext, aRenderingContext, + aDirtyRect); + nsresult rv = painter.PaintRowGroup(this); + if (NS_FAILED(rv)) return rv; + aFlags |= NS_PAINT_FLAG_TABLE_BG_PAINT; + } + } PRUint8 overflow = GetStyleDisplay()->mOverflow; PRBool clip = overflow == NS_STYLE_OVERFLOW_HIDDEN || @@ -213,7 +231,8 @@ NS_METHOD nsTableRowGroupFrame::Paint(nsIPresContext* aPresContext, aRenderingContext.PushState(); SetOverflowClipRect(aRenderingContext); } - PaintChildren(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer, aFlags); + PaintChildren(aPresContext, aRenderingContext, aDirtyRect, + aWhichLayer, aFlags); if (clip) { PRBool clipState; aRenderingContext.PopState(clipState); @@ -286,9 +305,9 @@ nsTableRowGroupFrame::GetFrameForPoint(nsIPresContext* aPresContext, // aKidRect is relative to the upper-left origin of our frame void nsTableRowGroupFrame::PlaceChild(nsIPresContext* aPresContext, - nsRowGroupReflowState& aReflowState, - nsIFrame* aKidFrame, - nsHTMLReflowMetrics& aDesiredSize) + nsRowGroupReflowState& aReflowState, + nsIFrame* aKidFrame, + nsHTMLReflowMetrics& aDesiredSize) { // Place and size the child FinishReflowChild(aKidFrame, aPresContext, nsnull, aDesiredSize, 0, aReflowState.y, 0); @@ -1854,6 +1873,24 @@ nsTableRowGroupFrame::GetBCBorderWidth(float aPixelsToTwips, return &aBorder; } +void nsTableRowGroupFrame::SetContinuousBCBorderWidth(PRUint8 aForSide, + BCPixelSize aPixelValue) +{ + switch (aForSide) { + case NS_SIDE_RIGHT: + mRightContBorderWidth = aPixelValue; + return; + case NS_SIDE_BOTTOM: + mBottomContBorderWidth = aPixelValue; + return; + case NS_SIDE_LEFT: + mLeftContBorderWidth = aPixelValue; + return; + default: + NS_ERROR("invalid NS_SIDE argument"); + } +} + //nsILineIterator methods for nsTableFrame NS_IMETHODIMP nsTableRowGroupFrame::GetNumLines(PRInt32* aResult) diff --git a/mozilla/layout/html/table/src/nsTableRowGroupFrame.h b/mozilla/layout/html/table/src/nsTableRowGroupFrame.h index bf62b14627c..d865aad1c96 100644 --- a/mozilla/layout/html/table/src/nsTableRowGroupFrame.h +++ b/mozilla/layout/html/table/src/nsTableRowGroupFrame.h @@ -41,6 +41,7 @@ #include "nsHTMLContainerFrame.h" #include "nsIAtom.h" #include "nsILineIterator.h" +#include "nsTablePainter.h" class nsTableFrame; class nsTableRowFrame; @@ -220,6 +221,22 @@ public: nsMargin* GetBCBorderWidth(float aPixelsToTwips, nsMargin& aBorder); + + /** + * Gets inner border widths before collapsing with cell borders + * Caller must get top border from previous row group or from table + * GetContinuousBCBorderWidth will not overwrite aBorder.top + * see nsTablePainter about continuous borders + */ + void GetContinuousBCBorderWidth(float aPixelsToTwips, + nsMargin& aBorder); + /** + * Sets full border widths before collapsing with cell borders + * @param aForSide - side to set; only right, left, and bottom valid + */ + void SetContinuousBCBorderWidth(PRUint8 aForSide, + BCPixelSize aPixelValue); + // nsILineIterator methods public: NS_IMETHOD GetNumLines(PRInt32* aResult); @@ -359,6 +376,13 @@ protected: void UndoContinuedRow(nsIPresContext* aPresContext, nsTableRowFrame* aRow); + +private: + // border widths in pixels in the collapsing border model + BCPixelSize mRightContBorderWidth; + BCPixelSize mBottomContBorderWidth; + BCPixelSize mLeftContBorderWidth; + public: virtual nsIFrame* GetFirstFrame() { return mFrames.FirstChild(); }; virtual nsIFrame* GetLastFrame() { return mFrames.LastChild(); }; @@ -419,4 +443,17 @@ inline void nsTableRowGroupFrame::SetHasStyleHeight(PRBool aValue) mState &= ~NS_ROWGROUP_HAS_STYLE_HEIGHT; } } + +inline void +nsTableRowGroupFrame::GetContinuousBCBorderWidth(float aPixelsToTwips, + nsMargin& aBorder) +{ + aBorder.right = BC_BORDER_LEFT_HALF_COORD(aPixelsToTwips, + mRightContBorderWidth); + aBorder.bottom = BC_BORDER_TOP_HALF_COORD(aPixelsToTwips, + mBottomContBorderWidth); + aBorder.left = BC_BORDER_RIGHT_HALF_COORD(aPixelsToTwips, + mLeftContBorderWidth); + return; +} #endif diff --git a/mozilla/layout/style/html.css b/mozilla/layout/style/html.css index f992dbc1bd3..e861052fd8a 100644 --- a/mozilla/layout/style/html.css +++ b/mozilla/layout/style/html.css @@ -150,7 +150,7 @@ plaintext, xmp, pre { table { display: table; - border-spacing: 2px; + border-spacing: 2px; border-collapse: separate; margin-top: 0; margin-bottom: 0; @@ -170,11 +170,6 @@ table[align="right"] { table[rules] { border-collapse: collapse; } - -/* make sure backgrounds are inherited in tables -- see bug 4510 */ -td, th, tr { - background: inherit; -} /* caption inherits from table not table-outer */ caption { diff --git a/mozilla/layout/style/nsStyleStruct.cpp b/mozilla/layout/style/nsStyleStruct.cpp index d4d217a5c21..ccbb0245ba5 100644 --- a/mozilla/layout/style/nsStyleStruct.cpp +++ b/mozilla/layout/style/nsStyleStruct.cpp @@ -538,16 +538,24 @@ void nsStyleBorder::RecalcData() } if ((mBorderStyle[NS_SIDE_TOP] & BORDER_COLOR_DEFINED) == 0) { - mBorderStyle[NS_SIDE_TOP] = BORDER_COLOR_DEFINED | BORDER_COLOR_FOREGROUND; + NS_ASSERTION(!(mBorderStyle[NS_SIDE_TOP] & BORDER_COLOR_SPECIAL), + "Clearing special border because BORDER_COLOR_DEFINED is not set"); + SetBorderToForeground(NS_SIDE_TOP); } if ((mBorderStyle[NS_SIDE_BOTTOM] & BORDER_COLOR_DEFINED) == 0) { - mBorderStyle[NS_SIDE_BOTTOM] = BORDER_COLOR_DEFINED | BORDER_COLOR_FOREGROUND; + NS_ASSERTION(!(mBorderStyle[NS_SIDE_BOTTOM] & BORDER_COLOR_SPECIAL), + "Clearing special border because BORDER_COLOR_DEFINED is not set"); + SetBorderToForeground(NS_SIDE_BOTTOM); } - if ((mBorderStyle[NS_SIDE_LEFT]& BORDER_COLOR_DEFINED) == 0) { - mBorderStyle[NS_SIDE_LEFT] = BORDER_COLOR_DEFINED | BORDER_COLOR_FOREGROUND; + if ((mBorderStyle[NS_SIDE_LEFT] & BORDER_COLOR_DEFINED) == 0) { + NS_ASSERTION(!(mBorderStyle[NS_SIDE_LEFT] & BORDER_COLOR_SPECIAL), + "Clearing special border because BORDER_COLOR_DEFINED is not set"); + SetBorderToForeground(NS_SIDE_LEFT); } if ((mBorderStyle[NS_SIDE_RIGHT] & BORDER_COLOR_DEFINED) == 0) { - mBorderStyle[NS_SIDE_RIGHT] = BORDER_COLOR_DEFINED | BORDER_COLOR_FOREGROUND; + NS_ASSERTION(!(mBorderStyle[NS_SIDE_RIGHT] & BORDER_COLOR_SPECIAL), + "Clearing special border because BORDER_COLOR_DEFINED is not set"); + SetBorderToForeground(NS_SIDE_RIGHT); } } diff --git a/mozilla/layout/style/quirk.css b/mozilla/layout/style/quirk.css index e1100e67c6c..9700d3b86ed 100644 --- a/mozilla/layout/style/quirk.css +++ b/mozilla/layout/style/quirk.css @@ -110,6 +110,10 @@ table { font-variant: -moz-initial; } +/* make sure backgrounds are inherited in tables -- see bug 4510*/ +td, th, tr { + background: inherit; +} /* Quirk: collapse top margin of BODY and TD and bottom margin of TD */ diff --git a/mozilla/layout/tables/nsCellMap.cpp b/mozilla/layout/tables/nsCellMap.cpp index 077cd9b0154..9675d80853b 100644 --- a/mozilla/layout/tables/nsCellMap.cpp +++ b/mozilla/layout/tables/nsCellMap.cpp @@ -88,11 +88,11 @@ nsTableCellMap::nsTableCellMap(nsTableFrame& aTableFrame, NS_ASSERTION(orderedRowGroups.Count() == (PRInt32) numRowGroups,"problem in OrderRowGroups"); for (PRUint32 rgX = 0; rgX < numRowGroups; rgX++) { - nsTableRowGroupFrame* rgFrame = - aTableFrame.GetRowGroupFrame((nsIFrame*)orderedRowGroups.ElementAt(rgX)); + nsTableRowGroupFrame* rgFrame = + nsTableFrame::GetRowGroupFrame((nsIFrame*)orderedRowGroups.ElementAt(rgX)); if (rgFrame) { - nsTableRowGroupFrame* prior = (0 == rgX) - ? nsnull : aTableFrame.GetRowGroupFrame((nsIFrame*)orderedRowGroups.ElementAt(rgX - 1)); + nsTableRowGroupFrame* prior = (0 == rgX) + ? nsnull : nsTableFrame::GetRowGroupFrame((nsIFrame*)orderedRowGroups.ElementAt(rgX - 1)); InsertGroupCellMap(*rgFrame, prior); } } diff --git a/mozilla/layout/tables/nsTableCellFrame.cpp b/mozilla/layout/tables/nsTableCellFrame.cpp index 2bcfaf7d94c..4752f803e86 100644 --- a/mozilla/layout/tables/nsTableCellFrame.cpp +++ b/mozilla/layout/tables/nsTableCellFrame.cpp @@ -40,6 +40,7 @@ #include "nsTableCellFrame.h" #include "nsTableFrame.h" #include "nsTableRowGroupFrame.h" +#include "nsTablePainter.h" #include "nsReflowPath.h" #include "nsStyleContext.h" #include "nsStyleConsts.h" @@ -376,30 +377,23 @@ nsTableCellFrame::PaintUnderlay(nsIPresContext& aPresContext, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, PRUint32& aFlags, - const nsStyleTableBorder& aCellTableStyle, const nsStyleBorder& aStyleBorder, const nsStylePadding& aStylePadding, - PRBool aVisibleBackground, - PRBool& aPaintChildren) + const nsStyleTableBorder& aCellTableStyle) { - if (aVisibleBackground) { - nsRect rect(0, 0, mRect.width, mRect.height); - nsCSSRendering::PaintBackground(&aPresContext, aRenderingContext, this, - aDirtyRect, rect, aStyleBorder, aStylePadding, - PR_TRUE); - // draw the border only when there is content or showing empty cells - if (!GetContentEmpty() || NS_STYLE_TABLE_EMPTY_CELLS_SHOW == aCellTableStyle.mEmptyCells) { - PRIntn skipSides = GetSkipSides(); - nsCSSRendering::PaintBorder(&aPresContext, aRenderingContext, this, - aDirtyRect, rect, aStyleBorder, mStyleContext, skipSides); - } + nsRect rect(0, 0, mRect.width, mRect.height); + nsCSSRendering::PaintBackground(&aPresContext, aRenderingContext, this, + aDirtyRect, rect, aStyleBorder, aStylePadding, + PR_TRUE); + PRIntn skipSides = GetSkipSides(); + if (NS_STYLE_TABLE_EMPTY_CELLS_SHOW == aCellTableStyle.mEmptyCells || + !GetContentEmpty()) { + nsCSSRendering::PaintBorder(&aPresContext, aRenderingContext, this, + aDirtyRect, rect, aStyleBorder, mStyleContext, skipSides); } - - // tell Paint to paint the children - aPaintChildren = PR_TRUE; } -NS_METHOD +NS_IMETHODIMP nsTableCellFrame::Paint(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, @@ -412,10 +406,9 @@ nsTableCellFrame::Paint(nsIPresContext* aPresContext, return NS_OK; } - PRBool paintChildren = PR_TRUE; + PRBool paintChildren = PR_TRUE; if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) { - PRBool paintBackground = PR_FALSE; const nsStyleBorder* myBorder = nsnull; const nsStylePadding* myPadding = nsnull; const nsStyleTableBorder* cellTableStyle = nsnull; @@ -425,19 +418,20 @@ nsTableCellFrame::Paint(nsIPresContext* aPresContext, myPadding = GetStylePadding(); cellTableStyle = GetStyleTableBorder(); - // paint the background when the cell is not empty or when showing empty cells or background - paintBackground = (!GetContentEmpty() || - NS_STYLE_TABLE_EMPTY_CELLS_SHOW == cellTableStyle->mEmptyCells || - NS_STYLE_TABLE_EMPTY_CELLS_SHOW_BACKGROUND == cellTableStyle->mEmptyCells); - } - - PaintUnderlay(*aPresContext, aRenderingContext, aDirtyRect, aFlags, *cellTableStyle, - *myBorder, *myPadding, paintBackground, paintChildren); + // draw the border & background only when there is content or showing empty cells + if (NS_STYLE_TABLE_EMPTY_CELLS_HIDE != cellTableStyle->mEmptyCells || + !GetContentEmpty()) { + PaintUnderlay(*aPresContext, aRenderingContext, aDirtyRect, aFlags, + *myBorder, *myPadding, *cellTableStyle); + } - if (vis->IsVisible()) { const nsStyleBackground* myColor = GetStyleBackground(); DecorateForSelection(aPresContext, aRenderingContext,myColor); //ignore return value } + + paintChildren = !(aFlags & NS_PAINT_FLAG_TABLE_CELL_BG_PASS); + //flags were for us; remove them for our children + aFlags &= ~ (NS_PAINT_FLAG_TABLE_CELL_BG_PASS | NS_PAINT_FLAG_TABLE_BG_PAINT); } #ifdef DEBUG @@ -931,7 +925,7 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext, const nsStylePosition* pos = GetStylePosition(); // calculate the min cell width - nscoord onePixel = NSIntPixelsToTwips(1, p2t); + nscoord onePixel = NSIntPixelsToTwips(1, p2t); nscoord smallestMinWidth = 0; if (eCompatibility_NavQuirks == compatMode) { if ((pos->mWidth.GetUnit() != eStyleUnit_Coord) && @@ -1332,14 +1326,14 @@ nsBCTableCellFrame::PaintUnderlay(nsIPresContext& aPresContext, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, PRUint32& aFlags, - const nsStyleTableBorder& aCellTableStyle, const nsStyleBorder& aStyleBorder, const nsStylePadding& aStylePadding, - PRBool aVisibleBackground, - PRBool& aPaintChildren) + const nsStyleTableBorder& aCellTableStyle) { - // Draw the background only during pass1. - if (aVisibleBackground && !(aFlags & BORDER_COLLAPSE_BACKGROUNDS)) { + if (!(aFlags & NS_PAINT_FLAG_TABLE_BG_PAINT) + /*direct call; not table-based paint*/ || + (aFlags & NS_PAINT_FLAG_TABLE_CELL_BG_PASS) + /*table cell background only pass*/) { // make border-width reflect border-collapse assigned border GET_PIXELS_TO_TWIPS(&aPresContext, p2t); nsMargin borderWidth; @@ -1363,7 +1357,4 @@ nsBCTableCellFrame::PaintUnderlay(nsIPresContext& aPresContext, PR_TRUE); // borders are painted by nsTableFrame } - - // don't paint the children if it's pass1 - aPaintChildren = (aFlags & BORDER_COLLAPSE_BACKGROUNDS); } diff --git a/mozilla/layout/tables/nsTableCellFrame.h b/mozilla/layout/tables/nsTableCellFrame.h index fd2082c2e91..83ffeda3087 100644 --- a/mozilla/layout/tables/nsTableCellFrame.h +++ b/mozilla/layout/tables/nsTableCellFrame.h @@ -289,16 +289,13 @@ protected: friend class nsTableRowFrame; - // paint backgrounds and borders (in separate border model) if aVisibleBackground, always set aPaintChildren virtual void PaintUnderlay(nsIPresContext& aPresContext, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, PRUint32& aFlags, - const nsStyleTableBorder& aCellTableStyle, const nsStyleBorder& aStyleBorder, const nsStylePadding& aStylePadding, - PRBool aVisibleBackground, - PRBool& aPaintChildren); + const nsStyleTableBorder& aCellTableStyle); nsresult DecorateForSelection(nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, @@ -471,11 +468,9 @@ protected: nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, PRUint32& aFlags, - const nsStyleTableBorder& aCellTableStyle, const nsStyleBorder& aStyleBorder, const nsStylePadding& aStylePadding, - PRBool aVisibleBackground, - PRBool& aPaintChildren); + const nsStyleTableBorder& aCellTableStyle); private: diff --git a/mozilla/layout/tables/nsTableColFrame.cpp b/mozilla/layout/tables/nsTableColFrame.cpp index 8f14ebdefd2..84bdffc0721 100644 --- a/mozilla/layout/tables/nsTableColFrame.cpp +++ b/mozilla/layout/tables/nsTableColFrame.cpp @@ -118,6 +118,24 @@ nsStyleCoord nsTableColFrame::GetStyleWidth() const return returnWidth; } +void nsTableColFrame::SetContinuousBCBorderWidth(PRUint8 aForSide, + BCPixelSize aPixelValue) +{ + switch (aForSide) { + case NS_SIDE_TOP: + mTopContBorderWidth = aPixelValue; + return; + case NS_SIDE_RIGHT: + mRightContBorderWidth = aPixelValue; + return; + case NS_SIDE_BOTTOM: + mBottomContBorderWidth = aPixelValue; + return; + default: + NS_ERROR("invalid side arg"); + } +} + void nsTableColFrame::ResetSizingInfo() { memset(mWidths, WIDTH_NOT_SET, NUM_WIDTHS * sizeof(PRInt32)); @@ -135,8 +153,6 @@ nsTableColFrame::Paint(nsIPresContext* aPresContext, if (NS_SUCCEEDED(IsVisibleForPainting(aPresContext, aRenderingContext, PR_FALSE, &isVisible)) && !isVisible) { return NS_OK; } - - // Standards mode background painting removed. See bug 4510 return NS_OK; } diff --git a/mozilla/layout/tables/nsTableColFrame.h b/mozilla/layout/tables/nsTableColFrame.h index a315cd95a00..89afa9debf4 100644 --- a/mozilla/layout/tables/nsTableColFrame.h +++ b/mozilla/layout/tables/nsTableColFrame.h @@ -39,6 +39,7 @@ #include "nscore.h" #include "nsContainerFrame.h" +#include "nsTablePainter.h" class nsVoidArray; class nsTableCellFrame; @@ -169,9 +170,26 @@ public: void ResetSizingInfo(); nscoord GetLeftBorderWidth(float* aPixelsToTwips = nsnull); - void SetLeftBorderWidth(nscoord aWidth); + void SetLeftBorderWidth(BCPixelSize aWidth); nscoord GetRightBorderWidth(float* aPixelsToTwips = nsnull); - void SetRightBorderWidth(nscoord aWidth); + void SetRightBorderWidth(BCPixelSize aWidth); + + /** + * Gets inner border widths before collapsing with cell borders + * Caller must get left border from previous column or from table + * GetContinuousBCBorderWidth will not overwrite aBorder.left + * see nsTablePainter about continuous borders + * + * @return outer right border width (left inner for next column) + */ + nscoord GetContinuousBCBorderWidth(float aPixelsToTwips, + nsMargin& aBorder); + /** + * Set full border widths before collapsing with cell borders + * @param aForSide - side to set; only valid for top, right, and bottom + */ + void SetContinuousBCBorderWidth(PRUint8 aForSide, + BCPixelSize aPixelValue); void Dump(PRInt32 aIndent); @@ -182,8 +200,13 @@ protected: // the starting index of the column (starting at 0) that this col object represents // PRUint32 mColIndex: 16; - PRUint32 mLeftBorderWidth: 8; // stored as pixels - PRUint32 mRightBorderWidth: 8; // stored as pixels + + // border width in pixels + BCPixelSize mLeftBorderWidth; + BCPixelSize mRightBorderWidth; + BCPixelSize mTopContBorderWidth; + BCPixelSize mRightContBorderWidth; + BCPixelSize mBottomContBorderWidth; // Widths including MIN_CON, DES_CON, FIX_CON, MIN_ADJ, DES_ADJ, FIX_ADJ, PCT, PCT_ADJ, MIN_PRO, FINAL // Widths including MIN_CON, DES_CON, FIX_CON, MIN_ADJ, DES_ADJ, FIX_ADJ, PCT, PCT_ADJ, MIN_PRO, FINAL // XXX these could be stored as pixels and converted to twips for a savings of 10 x 2 bytes. @@ -191,7 +214,7 @@ protected: }; inline PRInt32 nsTableColFrame::GetColIndex() const -{ +{ return mColIndex; } @@ -206,7 +229,7 @@ inline nscoord nsTableColFrame::GetLeftBorderWidth(float* aPixelsToTwips) return width; } -inline void nsTableColFrame::SetLeftBorderWidth(nscoord aWidth) +inline void nsTableColFrame::SetLeftBorderWidth(BCPixelSize aWidth) { mLeftBorderWidth = aWidth; } @@ -217,10 +240,23 @@ inline nscoord nsTableColFrame::GetRightBorderWidth(float* aPixelsToTwips) return width; } -inline void nsTableColFrame::SetRightBorderWidth(nscoord aWidth) +inline void nsTableColFrame::SetRightBorderWidth(BCPixelSize aWidth) { mRightBorderWidth = aWidth; } +inline nscoord +nsTableColFrame::GetContinuousBCBorderWidth(float aPixelsToTwips, + nsMargin& aBorder) +{ + aBorder.top = BC_BORDER_BOTTOM_HALF_COORD(aPixelsToTwips, + mTopContBorderWidth); + aBorder.right = BC_BORDER_LEFT_HALF_COORD(aPixelsToTwips, + mRightContBorderWidth); + aBorder.bottom = BC_BORDER_TOP_HALF_COORD(aPixelsToTwips, + mBottomContBorderWidth); + return BC_BORDER_RIGHT_HALF_COORD(aPixelsToTwips, mRightContBorderWidth); +} + #endif diff --git a/mozilla/layout/tables/nsTableColGroupFrame.cpp b/mozilla/layout/tables/nsTableColGroupFrame.cpp index 287302b06a6..cf49ce180f2 100644 --- a/mozilla/layout/tables/nsTableColGroupFrame.cpp +++ b/mozilla/layout/tables/nsTableColGroupFrame.cpp @@ -391,8 +391,6 @@ nsTableColGroupFrame::Paint(nsIPresContext* aPresContext, return NS_OK; } - // Standards mode background painting removed. See bug 4510 - PaintChildren(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer); return NS_OK; } @@ -646,6 +644,36 @@ void nsTableColGroupFrame::DeleteColFrame(nsIPresContext* aPresContext, nsTableC mFrames.DestroyFrame(aPresContext, aColFrame); } + +void nsTableColGroupFrame::SetContinuousBCBorderWidth(PRUint8 aForSide, + BCPixelSize aPixelValue) +{ + switch (aForSide) { + case NS_SIDE_TOP: + mTopContBorderWidth = aPixelValue; + return; + case NS_SIDE_BOTTOM: + mBottomContBorderWidth = aPixelValue; + return; + default: + NS_ERROR("invalid side arg"); + } +} + +void nsTableColGroupFrame::GetContinuousBCBorderWidth(float aPixelsToTwips, + nsMargin& aBorder) +{ + nsTableFrame* table; + nsTableFrame::GetTableFrame(this, table); + nsTableColFrame* col = table->GetColFrame(mStartColIndex + mColCount - 1); + col->GetContinuousBCBorderWidth(aPixelsToTwips, aBorder); + aBorder.top = BC_BORDER_BOTTOM_HALF_COORD(aPixelsToTwips, + mTopContBorderWidth); + aBorder.bottom = BC_BORDER_TOP_HALF_COORD(aPixelsToTwips, + mBottomContBorderWidth); + return; +} + /* ----- global methods ----- */ nsresult diff --git a/mozilla/layout/tables/nsTableColGroupFrame.h b/mozilla/layout/tables/nsTableColGroupFrame.h index ec9ff488bf1..6f5aa4ad673 100644 --- a/mozilla/layout/tables/nsTableColGroupFrame.h +++ b/mozilla/layout/tables/nsTableColGroupFrame.h @@ -40,9 +40,9 @@ #include "nscore.h" #include "nsHTMLContainerFrame.h" #include "nsTableColFrame.h" +#include "nsTablePainter.h" class nsTableColFrame; -class nsTableFrame; enum nsTableColGroupType { eColGroupContent = 0, // there is real col group content associated @@ -183,6 +183,21 @@ public: static void ResetColIndices(nsIFrame* aFirstColGroup, PRInt32 aFirstColIndex, nsIFrame* aStartColFrame = nsnull); + + /** + * Gets inner border widths before collapsing with cell borders + * Caller must get left border from previous column + * GetContinuousBCBorderWidth will not overwrite aBorder.left + * see nsTablePainter about continuous borders + */ + void GetContinuousBCBorderWidth(float aPixelsToTwips, + nsMargin& aBorder); + /** + * Set full border widths before collapsing with cell borders + * @param aForSide - side to set; only accepts top and bottom + */ + void SetContinuousBCBorderWidth(PRUint8 aForSide, + BCPixelSize aPixelValue); protected: nsTableColGroupFrame(); @@ -221,6 +236,10 @@ protected: PRInt32 mColCount; // the starting column index this col group represents. Must be >= 0. PRInt32 mStartColIndex; + + // border width in pixels + BCPixelSize mTopContBorderWidth; + BCPixelSize mBottomContBorderWidth; }; inline nsTableColGroupFrame::nsTableColGroupFrame() diff --git a/mozilla/layout/tables/nsTableFrame.cpp b/mozilla/layout/tables/nsTableFrame.cpp index 39747e63ccd..6a60f0021c6 100644 --- a/mozilla/layout/tables/nsTableFrame.cpp +++ b/mozilla/layout/tables/nsTableFrame.cpp @@ -50,6 +50,7 @@ #include "nsTableRowFrame.h" #include "nsTableRowGroupFrame.h" #include "nsTableOuterFrame.h" +#include "nsTablePainter.h" #include "nsHTMLValue.h" #include "BasicTableLayoutStrategy.h" @@ -126,18 +127,21 @@ struct nsTableReflowState { nsTableFrame* table = (nsTableFrame*)aTableFrame.GetFirstInFlow(); nsMargin borderPadding = table->GetChildAreaOffset(&reflowState); + nscoord cellSpacingX = table->GetCellSpacingX(); - x = borderPadding.left; - y = borderPadding.top; + x = borderPadding.left + cellSpacingX; + y = borderPadding.top; //cellspacing added during reflow availSize.width = aAvailWidth; if (NS_UNCONSTRAINEDSIZE != availSize.width) { - availSize.width -= borderPadding.left + borderPadding.right; + availSize.width -= borderPadding.left + borderPadding.right + + (2 * cellSpacingX); } availSize.height = aAvailHeight; if (NS_UNCONSTRAINEDSIZE != availSize.height) { - availSize.height -= borderPadding.top + borderPadding.bottom + (2 * table->GetCellSpacingY()); + availSize.height -= borderPadding.top + borderPadding.bottom + + (2 * table->GetCellSpacingY()); } footerFrame = nsnull; @@ -288,7 +292,7 @@ nsTableFrame::~nsTableFrame() if (nsnull!=mCellMap) { delete mCellMap; mCellMap = nsnull; - } + } if (nsnull!=mTableLayoutStrategy) { delete mTableLayoutStrategy; @@ -1230,7 +1234,7 @@ void nsTableFrame::AppendRowGroups(nsIPresContext& aPresContext, nsTableRowGroupFrame* nsTableFrame::GetRowGroupFrame(nsIFrame* aFrame, - nsIAtom* aFrameTypeIn) const + nsIAtom* aFrameTypeIn) { nsIFrame* rgFrame = nsnull; nsIAtom* frameType = aFrameTypeIn; @@ -1386,43 +1390,54 @@ nsTableFrame::Paint(nsIPresContext* aPresContext, nsFramePaintLayer aWhichLayer, PRUint32 aFlags) { - PRBool visibleBCBorders = PR_FALSE; if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) { + TableBackgroundPainter painter(this, TableBackgroundPainter::eOrigin_Table, + aPresContext, aRenderingContext, aDirtyRect); + nsresult rv; + + if (eCompatibility_NavQuirks == aPresContext->CompatibilityMode()) { + nsMargin deflate(0,0,0,0); + if (IsBorderCollapse()) { + GET_PIXELS_TO_TWIPS(aPresContext, p2t); + BCPropertyData* propData = + (BCPropertyData*)nsTableFrame::GetProperty(aPresContext, + (nsIFrame*)this, + nsLayoutAtoms::tableBCProperty, + PR_FALSE); + if (propData) { + deflate.top = BC_BORDER_TOP_HALF_COORD(p2t, propData->mTopBorderWidth); + deflate.right = BC_BORDER_RIGHT_HALF_COORD(p2t, propData->mRightBorderWidth); + deflate.bottom = BC_BORDER_BOTTOM_HALF_COORD(p2t, propData->mBottomBorderWidth); + deflate.left = BC_BORDER_LEFT_HALF_COORD(p2t, propData->mLeftBorderWidth); + } + } + rv = painter.QuirksPaintTable(this, deflate); + if (NS_FAILED(rv)) return rv; + } + else { + rv = painter.PaintTable(this); + if (NS_FAILED(rv)) return rv; + } + if (GetStyleVisibility()->IsVisible()) { const nsStyleBorder* border = GetStyleBorder(); - const nsStylePadding* padding = GetStylePadding(); nsRect rect(0, 0, mRect.width, mRect.height); - - nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this, - aDirtyRect, rect, *border, *padding, - PR_TRUE); - - // paint the border here only for separate borders if (!IsBorderCollapse()) { PRIntn skipSides = GetSkipSides(); nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this, - aDirtyRect, rect, *border, mStyleContext, skipSides); + aDirtyRect, rect, *border, mStyleContext, + skipSides); } else { - visibleBCBorders = PR_TRUE; + PaintBCBorders(aPresContext, aRenderingContext, aDirtyRect); } } + aFlags |= NS_PAINT_FLAG_TABLE_BG_PAINT; + aFlags &= ~NS_PAINT_FLAG_TABLE_CELL_BG_PASS; } - // for collapsed borders paint the backgrounds of cells, but not their contents (that happens below) - PRUint32 flags = aFlags; - if (visibleBCBorders) { - flags &= ~BORDER_COLLAPSE_BACKGROUNDS; // set bit to 0 - } - PaintChildren(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer, flags); - - if (visibleBCBorders) { - // for collapsed borders, paint the borders and then the backgrounds of cell - // contents but not the backgrounds of the cells - PaintBCBorders(aPresContext, aRenderingContext, aDirtyRect); - flags |= BORDER_COLLAPSE_BACKGROUNDS; // set bit to 1 - PaintChildren(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer, flags); - } + PaintChildren(aPresContext, aRenderingContext, aDirtyRect, + aWhichLayer, aFlags); #ifdef DEBUG // for debug... @@ -1583,16 +1598,19 @@ nsTableFrame::AdjustSiblingsAfterReflow(nsIPresContext* aPresContext, return NS_OK; } -void +void nsTableFrame::SetColumnDimensions(nscoord aHeight, const nsMargin& aBorderPadding) { - nscoord colHeight = aHeight -= aBorderPadding.top + aBorderPadding.bottom; nscoord cellSpacingX = GetCellSpacingX(); + nscoord cellSpacingY = GetCellSpacingY(); + nscoord colHeight = aHeight -= aBorderPadding.top + aBorderPadding.bottom + + 2* cellSpacingY; nsIFrame* colGroupFrame = mColGroups.FirstChild(); PRInt32 colX = 0; - nsPoint colGroupOrigin(aBorderPadding.left + cellSpacingX, aBorderPadding.top); + nsPoint colGroupOrigin(aBorderPadding.left + cellSpacingX, + aBorderPadding.top + cellSpacingY); PRInt32 numCols = GetColCount(); while (nsnull != colGroupFrame) { nscoord colGroupWidth = 0; @@ -1606,19 +1624,19 @@ nsTableFrame::SetColumnDimensions(nscoord aHeight, nsRect colRect(colOrigin.x, colOrigin.y, colWidth, colHeight); colFrame->SetRect(colRect); colOrigin.x += colWidth + cellSpacingX; - - colGroupWidth += colWidth; - if (numCols - 1 != colX) { - colGroupWidth += cellSpacingX; - } + colGroupWidth += colWidth + cellSpacingX; colX++; } colFrame = colFrame->GetNextSibling(); } + if (colGroupWidth) { + colGroupWidth -= cellSpacingX; + } + nsRect colGroupRect(colGroupOrigin.x, colGroupOrigin.y, colGroupWidth, colHeight); colGroupFrame->SetRect(colGroupRect); colGroupFrame = colGroupFrame->GetNextSibling(); - colGroupOrigin.x += colGroupWidth; + colGroupOrigin.x += colGroupWidth + cellSpacingX; } } @@ -2881,7 +2899,7 @@ nsTableFrame::RecoverState(nsTableReflowState& aReflowState, if ((NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == display->mDisplay) && !aReflowState.footerFrame) { aReflowState.footerFrame = childFrame; - } + } else { if ((NS_STYLE_DISPLAY_TABLE_ROW_GROUP == display->mDisplay) && !aReflowState.firstBodySection) { @@ -3647,7 +3665,7 @@ nsTableFrame::DistributeHeightToRows(const nsHTMLReflowState& aReflowState, } yOriginRow += rowRect.height + cellSpacingY; yEndRG += rowRect.height + cellSpacingY; - } + } rowFrame = rowFrame->GetNextRow(); } if (amountUsed > 0) { @@ -5658,7 +5676,7 @@ nsTableFrame::CalcBCBorders(nsIPresContext& aPresContext) BCCellBorder lastTopBorder, lastBottomBorder; // horizontal borders indexed in x-direction (cols) BCCellBorders lastBottomBorders(damageArea.width + 1, damageArea.x); if (!lastBottomBorders.borders) ABORT0(); - PRBool startSeg; + PRBool startSeg, gotRowBorder; BCMapCellInfo info, ajaInfo; BCBorderOwner owner, ajaOwner; @@ -5680,6 +5698,7 @@ nsTableFrame::CalcBCBorders(nsIPresContext& aPresContext) PRBool bottomRowSpan = PR_FALSE; // see if lastTopBorder, lastBottomBorder need to be reset if (iter.IsNewRow()) { + gotRowBorder = PR_FALSE; lastTopBorder.Reset(info.rowIndex, info.rowSpan); lastBottomBorder.Reset(cellEndRowIndex + 1, info.rowSpan); } @@ -5722,7 +5741,7 @@ nsTableFrame::CalcBCBorders(nsIPresContext& aPresContext) // update lastTopBorder and see if a new segment starts startSeg = SetHorBorder(ownerBStyle, ownerWidth, ownerColor, tlCorner, lastTopBorder); // store the border segment in the cell map - tableCellMap->SetBCBorderEdge(NS_SIDE_TOP, *info.cellMap, 0, 0, colX, + tableCellMap->SetBCBorderEdge(NS_SIDE_TOP, *info.cellMap, 0, 0, colX, 1, owner, ownerWidth, startSeg); // update the affected borders of the cell, row, and table DivideBCBorderSize(ownerWidth, smallHalf, largeHalf); @@ -5733,6 +5752,44 @@ nsTableFrame::CalcBCBorders(nsIPresContext& aPresContext) info.topRow->SetTopBCBorderWidth(PR_MAX(smallHalf, info.topRow->GetTopBCBorderWidth())); } propData->mTopBorderWidth = LimitBorderWidth(PR_MAX(propData->mTopBorderWidth, (PRUint8)ownerWidth)); + //calculate column continuous borders + //we only need to do this once, so we'll do it only on the first row + CalcDominantBorder(this, cgFrame, colFrame, info.rg, info.topRow, + nsnull, PR_TRUE, NS_SIDE_TOP, PR_FALSE, t2p, + owner, ownerBStyle, ownerWidth, ownerColor); + ((nsTableColFrame*)colFrame)->SetContinuousBCBorderWidth(NS_SIDE_TOP, + ownerWidth); + if (numCols == cellEndColIndex + 1) { + CalcDominantBorder(this, cgFrame, colFrame, nsnull, nsnull, + nsnull, PR_TRUE, NS_SIDE_RIGHT, PR_FALSE, t2p, + owner, ownerBStyle, ownerWidth, ownerColor); + } + else { + CalcDominantBorder(nsnull, cgFrame, colFrame, nsnull, nsnull, + nsnull, PR_FALSE, NS_SIDE_RIGHT, PR_FALSE, t2p, + owner, ownerBStyle, ownerWidth, ownerColor); + } + ((nsTableColFrame*)colFrame)->SetContinuousBCBorderWidth(NS_SIDE_RIGHT, + ownerWidth); + } + //calculate continuous top first row & rowgroup border: special case + //because it must include the table in the collapse + CalcDominantBorder(this, nsnull, nsnull, info.rg, info.topRow, + nsnull, PR_TRUE, NS_SIDE_TOP, PR_FALSE, t2p, + owner, ownerBStyle, ownerWidth, ownerColor); + info.topRow->SetContinuousBCBorderWidth(NS_SIDE_TOP, ownerWidth); + if (info.cgRight) { + //calculate continuous top colgroup border once per colgroup + CalcDominantBorder(this, info.cg, nsnull, info.rg, info.topRow, + nsnull, PR_TRUE, NS_SIDE_TOP, PR_FALSE, t2p, + owner, ownerBStyle, ownerWidth, ownerColor); + info.cg->SetContinuousBCBorderWidth(NS_SIDE_TOP, ownerWidth); + } + if (0 == info.colIndex) { + CalcDominantBorder(this, info.cg, info.leftCol, nsnull, nsnull, + nsnull, PR_TRUE, NS_SIDE_LEFT, PR_FALSE, t2p, + owner, ownerBStyle, ownerWidth, ownerColor); + mBits.mLeftContBCBorder = ownerWidth; } } else { @@ -5760,10 +5817,10 @@ nsTableFrame::CalcBCBorders(nsIPresContext& aPresContext) nsTableRowFrame* rowFrame = nsnull; for (PRInt32 rowX = info.rowIndex; rowX <= cellEndRowIndex; rowX++) { rowFrame = (rowX == info.rowIndex) ? info.topRow : rowFrame->GetNextRow(); - CalcDominantBorder(this, info.cg, info.leftCol, info.rg, rowFrame, info.cell, PR_TRUE, NS_SIDE_LEFT, + CalcDominantBorder(this, info.cg, info.leftCol, info.rg, rowFrame, info.cell, PR_TRUE, NS_SIDE_LEFT, PR_FALSE, t2p, owner, ownerBStyle, ownerWidth, ownerColor); BCCornerInfo& tlCorner = (0 == rowX) ? topCorners[0] : bottomCorners[0]; // top left - tlCorner.Update(NS_SIDE_BOTTOM, owner, ownerBStyle, ownerWidth, ownerColor); + tlCorner.Update(NS_SIDE_BOTTOM, owner, ownerBStyle, ownerWidth, ownerColor); tableCellMap->SetBCBorderCorner(eTopLeft, *info.cellMap, iter.mRowGroupStart, rowX, 0, tlCorner.ownerSide, tlCorner.subWidth, tlCorner.bevel); bottomCorners[0].Set(NS_SIDE_TOP, owner, ownerBStyle, ownerWidth, ownerColor); // bottom left @@ -5781,6 +5838,17 @@ nsTableFrame::CalcBCBorders(nsIPresContext& aPresContext) info.leftCol->SetLeftBorderWidth(PR_MAX(smallHalf, info.leftCol->GetLeftBorderWidth())); } propData->mLeftBorderWidth = LimitBorderWidth(PR_MAX(propData->mLeftBorderWidth, ownerWidth)); + //get row continuous borders + CalcDominantBorder(this, info.cg, info.leftCol, info.rg, rowFrame, nsnull, PR_TRUE, NS_SIDE_LEFT, + PR_FALSE, t2p, owner, ownerBStyle, ownerWidth, ownerColor); + rowFrame->SetContinuousBCBorderWidth(NS_SIDE_LEFT, ownerWidth); + } + //get row group continuous borders + if (info.rgBottom) { //once per row group, so check for bottom + CalcDominantBorder(this, info.cg, info.leftCol, info.rg, nsnull, + nsnull, PR_TRUE, NS_SIDE_LEFT, PR_FALSE, t2p, + owner, ownerBStyle, ownerWidth, ownerColor); + info.rg->SetContinuousBCBorderWidth(NS_SIDE_LEFT, ownerWidth); } } @@ -5818,6 +5886,18 @@ nsTableFrame::CalcBCBorders(nsIPresContext& aPresContext) info.rightCol->SetRightBorderWidth(PR_MAX(largeHalf, info.rightCol->GetRightBorderWidth())); } propData->mRightBorderWidth = LimitBorderWidth(PR_MAX(propData->mRightBorderWidth, ownerWidth)); + //get row continuous borders + CalcDominantBorder(this, info.cg, info.rightCol, info.rg, rowFrame, + nsnull, PR_TRUE, NS_SIDE_RIGHT, PR_TRUE, t2p, + owner, ownerBStyle, ownerWidth, ownerColor); + rowFrame->SetContinuousBCBorderWidth(NS_SIDE_RIGHT, ownerWidth); + } + //get row group continuous borders + if (info.rgBottom) { //once per rg, so check for bottom + CalcDominantBorder(this, info.cg, info.rightCol, info.rg, nsnull, + nsnull, PR_TRUE, NS_SIDE_RIGHT, PR_TRUE, t2p, + owner, ownerBStyle, ownerWidth, ownerColor); + info.rg->SetContinuousBCBorderWidth(NS_SIDE_RIGHT, ownerWidth); } } else { @@ -5944,17 +6024,32 @@ nsTableFrame::CalcBCBorders(nsIPresContext& aPresContext) lastBottomBorder.index = cellEndRowIndex + 1; lastBottomBorder.span = info.rowSpan; lastBottomBorders[colX] = lastBottomBorder; + //get col continuous border + CalcDominantBorder(this, cgFrame, colFrame, info.rg, info.bottomRow, + nsnull, PR_TRUE, NS_SIDE_BOTTOM, PR_TRUE, t2p, + owner, ownerBStyle, ownerWidth, ownerColor); + ((nsTableColFrame*)colFrame)->SetContinuousBCBorderWidth(NS_SIDE_BOTTOM, + ownerWidth); } + //get row group/col group continuous border + CalcDominantBorder(this, nsnull, nsnull, info.rg, info.bottomRow, + nsnull, PR_TRUE, NS_SIDE_BOTTOM, PR_TRUE, t2p, + owner, ownerBStyle, ownerWidth, ownerColor); + info.rg->SetContinuousBCBorderWidth(NS_SIDE_BOTTOM, ownerWidth); + CalcDominantBorder(this, info.cg, nsnull, info.rg, info.bottomRow, + nsnull, PR_TRUE, NS_SIDE_BOTTOM, PR_TRUE, t2p, + owner, ownerBStyle, ownerWidth, ownerColor); + info.cg->SetContinuousBCBorderWidth(NS_SIDE_BOTTOM, ownerWidth); } else { PRInt32 segLength = 0; for (PRInt32 colX = info.colIndex; colX <= cellEndColIndex; colX += segLength) { iter.PeekBottom(info, colX, ajaInfo); const nsIFrame* rg = (info.rgBottom) ? info.rg : nsnull; - CalcDominantBorder(nsnull, nsnull, nsnull, rg, info.bottomRow, info.cell, PR_FALSE, NS_SIDE_BOTTOM, + CalcDominantBorder(nsnull, nsnull, nsnull, rg, info.bottomRow, info.cell, PR_FALSE, NS_SIDE_BOTTOM, PR_TRUE, t2p, owner, ownerBStyle, ownerWidth, ownerColor); rg = (ajaInfo.rgTop) ? ajaInfo.rg : nsnull; - CalcDominantBorder(nsnull, nsnull, nsnull, rg, ajaInfo.topRow, ajaInfo.cell, PR_FALSE, NS_SIDE_TOP, + CalcDominantBorder(nsnull, nsnull, nsnull, rg, ajaInfo.topRow, ajaInfo.cell, PR_FALSE, NS_SIDE_TOP, PR_FALSE, t2p, ajaOwner, ajaBStyle, ajaWidth, ajaColor); CalcDominantBorder(PR_FALSE, owner, ownerBStyle, ownerWidth, ownerColor, ajaOwner, ajaBStyle, ajaWidth, ajaColor, owner, ownerBStyle, ownerWidth, ownerColor, PR_TRUE); @@ -5972,23 +6067,23 @@ nsTableFrame::CalcBCBorders(nsIPresContext& aPresContext) } else if (prevRowIndex < cellEndRowIndex + 1) { // spans below the cell to the left topCorners[colX] = blCorner; - blCorner.Set(NS_SIDE_RIGHT, owner, ownerBStyle, ownerWidth, ownerColor); + blCorner.Set(NS_SIDE_RIGHT, owner, ownerBStyle, ownerWidth, ownerColor); update = PR_FALSE; } } if (update) { - blCorner.Update(NS_SIDE_RIGHT, owner, ownerBStyle, ownerWidth, ownerColor); + blCorner.Update(NS_SIDE_RIGHT, owner, ownerBStyle, ownerWidth, ownerColor); } if (BOTTOM_DAMAGED(cellEndRowIndex) && LEFT_DAMAGED(colX)) { if (hitsSpanBelow) { - tableCellMap->SetBCBorderCorner(eBottomLeft, *info.cellMap, iter.mRowGroupStart, cellEndRowIndex, colX, + tableCellMap->SetBCBorderCorner(eBottomLeft, *info.cellMap, iter.mRowGroupStart, cellEndRowIndex, colX, blCorner.ownerSide, blCorner.subWidth, blCorner.bevel); } // store any corners this cell spans together with the aja cell for (PRInt32 cX = colX + 1; cX < colX + segLength; cX++) { - BCCornerInfo& corner = bottomCorners[cX]; + BCCornerInfo& corner = bottomCorners[cX]; corner.Set(NS_SIDE_RIGHT, owner, ownerBStyle, ownerWidth, ownerColor); - tableCellMap->SetBCBorderCorner(eBottomLeft, *info.cellMap, iter.mRowGroupStart, cellEndRowIndex, + tableCellMap->SetBCBorderCorner(eBottomLeft, *info.cellMap, iter.mRowGroupStart, cellEndRowIndex, cX, corner.ownerSide, corner.subWidth, PR_FALSE); } } @@ -6008,7 +6103,7 @@ nsTableFrame::CalcBCBorders(nsIPresContext& aPresContext) // store the border segment the cell map and update cellBorders if (BOTTOM_DAMAGED(cellEndRowIndex) && LEFT_DAMAGED(colX) && RIGHT_DAMAGED(colX)) { - tableCellMap->SetBCBorderEdge(NS_SIDE_BOTTOM, *info.cellMap, iter.mRowGroupStart, cellEndRowIndex, + tableCellMap->SetBCBorderEdge(NS_SIDE_BOTTOM, *info.cellMap, iter.mRowGroupStart, cellEndRowIndex, colX, segLength, owner, ownerWidth, startSeg); // update the borders of the affected cells and rows DivideBCBorderSize(ownerWidth, smallHalf, largeHalf); @@ -6027,16 +6122,39 @@ nsTableFrame::CalcBCBorders(nsIPresContext& aPresContext) } // update bottom right corner BCCornerInfo& brCorner = bottomCorners[colX + segLength]; - brCorner.Update(NS_SIDE_LEFT, owner, ownerBStyle, ownerWidth, ownerColor); + brCorner.Update(NS_SIDE_LEFT, owner, ownerBStyle, ownerWidth, ownerColor); + } + if (!gotRowBorder && 1 == info.rowSpan) { + //get continuous row/row group border + //we need to check the row group's bottom border if this is + //the last row in the row group, but only a cell with rowspan=1 + //will know whether *this* row is at the bottom + const nsIFrame* rg = (info.rgBottom) ? info.rg : nsnull; + CalcDominantBorder(nsnull, nsnull, nsnull, rg, info.bottomRow, + nsnull, PR_FALSE, NS_SIDE_BOTTOM, PR_TRUE, t2p, + owner, ownerBStyle, ownerWidth, ownerColor); + rg = (ajaInfo.rgTop) ? ajaInfo.rg : nsnull; + CalcDominantBorder(nsnull, nsnull, nsnull, rg, ajaInfo.topRow, + nsnull, PR_FALSE, NS_SIDE_TOP, PR_FALSE, t2p, + ajaOwner, ajaBStyle, ajaWidth, ajaColor); + CalcDominantBorder(PR_FALSE, owner, ownerBStyle, ownerWidth, + ownerColor, ajaOwner, ajaBStyle, ajaWidth, + ajaColor, owner, ownerBStyle, ownerWidth, + ownerColor, PR_TRUE); + ajaInfo.topRow->SetContinuousBCBorderWidth(NS_SIDE_TOP, ownerWidth); + if (info.rgBottom) { + info.rg->SetContinuousBCBorderWidth(NS_SIDE_BOTTOM, ownerWidth); + } + gotRowBorder = PR_TRUE; } } // see if the cell to the right had a rowspan and its lower left border needs be joined with this one's bottom - if ((numCols != cellEndColIndex + 1) && // there is a cell to the right + if ((numCols != cellEndColIndex + 1) && // there is a cell to the right (lastBottomBorders[cellEndColIndex + 1].span > 1)) { // cell to right was a rowspan BCCornerInfo& corner = bottomCorners[cellEndColIndex + 1]; if ((NS_SIDE_TOP != corner.ownerSide) && (NS_SIDE_BOTTOM != corner.ownerSide)) { // not a vertical owner - BCCellBorder& thisBorder = lastBottomBorder; + BCCellBorder& thisBorder = lastBottomBorder; BCCellBorder& nextBorder = lastBottomBorders[info.colIndex + 1]; if ((thisBorder.color == nextBorder.color) && (thisBorder.width == nextBorder.width) && (thisBorder.style == nextBorder.style)) { @@ -7206,7 +7324,7 @@ PRBool nsTableFrame::RowHasSpanningCells(PRInt32 aRowIndex) nsTableCellMap* cellMap = GetCellMap(); NS_PRECONDITION (cellMap, "bad call, cellMap not yet allocated."); if (cellMap) { - result = cellMap->RowHasSpanningCells(aRowIndex); + result = cellMap->RowHasSpanningCells(aRowIndex); } return result; } @@ -7217,7 +7335,7 @@ PRBool nsTableFrame::RowIsSpannedInto(PRInt32 aRowIndex) nsTableCellMap* cellMap = GetCellMap(); NS_PRECONDITION (cellMap, "bad call, cellMap not yet allocated."); if (cellMap) { - result = cellMap->RowIsSpannedInto(aRowIndex); + result = cellMap->RowIsSpannedInto(aRowIndex); } return result; } diff --git a/mozilla/layout/tables/nsTableFrame.h b/mozilla/layout/tables/nsTableFrame.h index 0ffff8c1072..0a95bbe0916 100644 --- a/mozilla/layout/tables/nsTableFrame.h +++ b/mozilla/layout/tables/nsTableFrame.h @@ -62,10 +62,6 @@ struct nsStylePosition; enum nsPixelRound {eAlwaysRoundUp=0, eAlwaysRoundDown, eRoundUpIfHalfOrMore}; -// flags for Paint, PaintChild, PaintChildren are currently only used by tables. -// use low order bit of flags to distinguish between pass1(0) and pass2(1) border collapse backgrounds -#define BORDER_COLLAPSE_BACKGROUNDS 0x00000001 - #ifdef DEBUG_TABLE_REFLOW_TIMING #ifdef WIN32 #include @@ -331,6 +327,14 @@ public: // the surrounding margin space nsMargin GetBCMargin(nsIPresContext* aPresContext) const; + /** Get width of table + colgroup + col collapse: elements that + * continue along the length of the whole left side. + * see nsTablePainter about continuous borders + * @param aPixelsToTwips - conversion factor + * @param aGetInner - get only inner half of border width + */ + nscoord GetContinuousLeftBCBorderWidth(float aPixelsToTwips) const; + void SetBCDamageArea(nsIPresContext& aPresContext, const nsRect& aValue); @@ -643,7 +647,7 @@ protected: nsTableReflowState& aReflowState, nsReflowStatus& aStatus); - /** process a style chnaged notification. + /** process a style changed notification. * @see nsIFrameReflow::Reflow * TODO: needs to be optimized for which attribute was actually changed. */ @@ -797,11 +801,10 @@ public: nsVoidArray& GetColCache(); - /** - * Return aFrame's child if aFrame is an nsScrollFrame, otherwise return aFrame - */ - nsTableRowGroupFrame* GetRowGroupFrame(nsIFrame* aFrame, - nsIAtom* aFrameTypeIn = nsnull) const; + /** Return aFrame's child if aFrame is an nsScrollFrame, otherwise return aFrame + */ + static nsTableRowGroupFrame* GetRowGroupFrame(nsIFrame* aFrame, + nsIAtom* aFrameTypeIn = nsnull); protected: @@ -908,20 +911,21 @@ protected: // DATA MEMBERS struct TableBits { - unsigned mHadInitialReflow:1; // has intial reflow happened - unsigned mHaveReflowedColGroups:1; // have the col groups gotten their initial reflow - unsigned mNeedStrategyBalance:1; // does the strategy needs to balance the table - unsigned mNeedStrategyInit:1; // does the strategy needs to be initialized and then balance the table - unsigned mHasPctCol:1; // does any cell or col have a pct width - unsigned mCellSpansPctCol:1; // does any cell span a col with a pct width (or containing a cell with a pct width) - unsigned mDidResizeReflow:1; // did a resize reflow happen (indicating pass 2) - unsigned mIsBorderCollapse:1; // border collapsing model vs. separate model - unsigned mRowInserted:1; - unsigned mNeedSpecialReflow:1; - unsigned mNeedToInitiateSpecialReflow:1; - unsigned mInitiatedSpecialReflow:1; - unsigned mNeedToCalcBCBorders:1; - unsigned : 19; // unused + PRUint32 mHadInitialReflow:1; // has intial reflow happened + PRUint32 mHaveReflowedColGroups:1; // have the col groups gotten their initial reflow + PRUint32 mNeedStrategyBalance:1; // does the strategy needs to balance the table + PRUint32 mNeedStrategyInit:1; // does the strategy needs to be initialized and then balance the table + PRUint32 mHasPctCol:1; // does any cell or col have a pct width + PRUint32 mCellSpansPctCol:1; // does any cell span a col with a pct width (or containing a cell with a pct width) + PRUint32 mDidResizeReflow:1; // did a resize reflow happen (indicating pass 2) + PRUint32 mIsBorderCollapse:1; // border collapsing model vs. separate model + PRUint32 mRowInserted:1; + PRUint32 mNeedSpecialReflow:1; + PRUint32 mNeedToInitiateSpecialReflow:1; + PRUint32 mInitiatedSpecialReflow:1; + PRUint32 mNeedToCalcBCBorders:1; + PRUint32 mLeftContBCBorder:8; + PRUint32 : 11; // unused } mBits; nsTableCellMap* mCellMap; // maintains the relationships between rows, cols, and cells @@ -1041,7 +1045,7 @@ inline void nsTableFrame::SetRowInserted(PRBool aValue) inline nsFrameList& nsTableFrame::GetColGroups() { - return mColGroups; + return NS_STATIC_CAST(nsTableFrame*, GetFirstInFlow())->mColGroups; } inline nsVoidArray& nsTableFrame::GetColCache() @@ -1084,6 +1088,12 @@ inline void nsTableFrame::SetNeedToCalcBCBorders(PRBool aValue) mBits.mNeedToCalcBCBorders = (unsigned)aValue; } +inline nscoord +nsTableFrame::GetContinuousLeftBCBorderWidth(float aPixelsToTwips) const +{ + return BC_BORDER_RIGHT_HALF_COORD(aPixelsToTwips, mBits.mLeftContBCBorder); +} + enum nsTableIteration { eTableLTR = 0, eTableRTL = 1, diff --git a/mozilla/layout/tables/nsTablePainter.cpp b/mozilla/layout/tables/nsTablePainter.cpp new file mode 100644 index 00000000000..170a3cd916f --- /dev/null +++ b/mozilla/layout/tables/nsTablePainter.cpp @@ -0,0 +1,685 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TableBackgroundPainter implementation. + * + * The Initial Developer of the Original Code is + * Elika J. Etemad ("fantasai") . + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsTableFrame.h" +#include "nsTableRowGroupFrame.h" +#include "nsTableRowFrame.h" +#include "nsTableColGroupFrame.h" +#include "nsTableColFrame.h" +#include "nsTableCellFrame.h" +#include "nsTablePainter.h" +#include "nsCSSRendering.h" + +/* ~*~ Standards Mode Painting ~*~ + + Background painting in Standards mode follows CSS2.1:17.5.1 + That section does not, however, describe the effect of + borders on background image positioning. What we do is: + + - in separate borders, the borders are passed in so that + their width figures in image positioning, even for rows/cols, which + don't have visible borders. This is done to allow authors + to position row backgrounds by, for example, aligning the + top left corner with the top left padding corner of the + top left table cell in the row in cases where all cells + have consistent border widths. If we didn't honor these + invisible borders, there would be no way to align + backgrounds with the padding edges, and designs would be + lost underneath the border. + + - in collapsing borders, because the borders collapse, we + use the -continuous border- width to synthesize a border + style and pass that in instead of using the element's + assigned style directly. + + The continuous border on a given edge of an element is + the collapse of all borders guaranteed to be continuous + along that edge. Cell borders are ignored (because, for + example, setting a thick border on the leftmost cell + should not shift the row background over; this way a + striped background set on will line up across rows + even if the cells are assigned arbitrary border widths. + + For example, the continous border on the top edge of a + row group is the collapse of any row group, row, and + table borders involved. (The first row group's top would + be [table-top + row group top + first row top]. It's bottom + would be [row group bottom + last row bottom + next row + top + next row group top].) + The top edge of a column group likewise includes the + table top, row group top, and first row top borders. However, + it *also* includes its own top border, since that is guaranteed + to be continuous. It does not include column borders because + those are not guaranteed to be continuous: there may be two + columns with different borders in a single column group. + + An alternative would be to define the continuous border as + [table? + row group + row] for horizontal + [table? + col group + col] for vertical + This makes it easier to line up backgrounds across elements + despite varying border widths, but it does not give much + flexibility in aligning /to/ those border widths. +*/ + +/* ~*~ Quirks Table Background Painting ~*~ + + Quirks inherits all backgrounds below the table level into the + cells; we don't paint intermediate backgrounds. +*/ + + +/* ~*~ TableBackgroundPainter ~*~ + + The TableBackgroundPainter is created and destroyed in one painting call. + Its principal function is PaintTable, which paints all table element + backgrounds. The initial code in that method sets up an array of column + data that caches the background styles and the border sizes for the + columns and colgroups in TableBackgroundData structs in mCols. Data for + BC borders are calculated and stashed in a synthesized border style struct + in the data struct since collapsed borders aren't the same width as style- + assigned borders. The data struct optimizes by only doing this if there's + an image background; otherwise we don't care. //XXX should also check background-origin + The class then loops through the row groups, rows, and cells. It uses + the mRowGroup and mRow TableBackgroundData structs to cache data for + the current frame in the loop. At the cell level, it paints the backgrounds, + one over the other, inside the cell rect. + + The exception to this pattern is when a table element has a view. + Elements with views are passed through, which means their data + (and their descendants' data) are not cached. The full loop is still + executed, however, so that underlying layers can get painted at the cell + level. + + The TableBackgroundPainter is then destroyed. + + Elements with views set up their own painter to finish the painting + process, since they were skipped. They call the appropriate sub-part + of the loop (e.g. PaintRow) which will paint the frame and descendants. + */ + +TableBackgroundPainter::TableBackgroundData::TableBackgroundData() + : mFrame(nsnull), + mBackground(nsnull), + mBorder(nsnull), + mSynthBorder(nsnull) +{ + MOZ_COUNT_CTOR(TableBackgroundData); +} + +TableBackgroundPainter::TableBackgroundData::~TableBackgroundData() +{ + NS_ASSERTION(!mSynthBorder, "must call Destroy before dtor"); + MOZ_COUNT_DTOR(TableBackgroundData); +} + +void +TableBackgroundPainter::TableBackgroundData::Destroy(nsIPresContext* aPresContext) +{ + NS_PRECONDITION(aPresContext, "null prescontext"); + if (mSynthBorder) { + mSynthBorder->Destroy(aPresContext); + mSynthBorder = nsnull; + } +} + +void +TableBackgroundPainter::TableBackgroundData::Clear() +{ + mRect.Empty(); + mFrame = nsnull; + mBorder = nsnull; + mBackground = nsnull; +} + +void +TableBackgroundPainter::TableBackgroundData::SetFrame(nsIFrame* aFrame) +{ + NS_PRECONDITION(aFrame, "null frame"); + mFrame = aFrame; + mRect = aFrame->GetRect(); +} + +void +TableBackgroundPainter::TableBackgroundData::SetFull(nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + nsIFrame* aFrame) +{ + NS_PRECONDITION(aFrame, "null frame"); + mFrame = aFrame; + mRect = aFrame->GetRect(); + /* IsVisibleForPainting doesn't use aRenderingContext except in nsTextFrames, + so we're not going to bother translating.*/ + PRBool isVisible; + nsresult rv = aFrame->IsVisibleForPainting(aPresContext, aRenderingContext, + PR_TRUE, &isVisible); + if (NS_SUCCEEDED(rv) && isVisible && + aFrame->GetStyleVisibility()->IsVisible()) { + mBackground = aFrame->GetStyleBackground(); + mBorder = aFrame->GetStyleBorder(); + } +} + +inline PRBool +TableBackgroundPainter::TableBackgroundData::ShouldSetBCBorder() +{ + /* we only need accurate border data when positioning background images*/ + return mBackground && !(mBackground->mBackgroundFlags & NS_STYLE_BG_IMAGE_NONE); +} + +nsresult +TableBackgroundPainter::TableBackgroundData::SetBCBorder(nsMargin& aBorder, + TableBackgroundPainter* aPainter) +{ + NS_PRECONDITION(aPainter, "null painter"); + if (!mSynthBorder) { + mSynthBorder = new (aPainter->mPresContext) + nsStyleBorder(aPainter->mZeroBorder); + if (!mSynthBorder) return NS_ERROR_OUT_OF_MEMORY; + } + + nsStyleCoord coord(aBorder.top); + mSynthBorder->mBorder.SetTop(coord); + coord.SetCoordValue(aBorder.right); + mSynthBorder->mBorder.SetRight(coord); + coord.SetCoordValue(aBorder.bottom); + mSynthBorder->mBorder.SetBottom(coord); + coord.SetCoordValue(aBorder.left); + mSynthBorder->mBorder.SetLeft(coord); + mSynthBorder->RecalcData(); + + mBorder = mSynthBorder; + return NS_OK; +} + +TableBackgroundPainter::TableBackgroundPainter(nsTableFrame* aTableFrame, + Origin aOrigin, + nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) + : mPresContext(aPresContext), + mRenderingContext(aRenderingContext), + mDirtyRect(aDirtyRect), + mOrigin(aOrigin), + mCols(nsnull), + mZeroBorder(aPresContext) +{ + MOZ_COUNT_CTOR(TableBackgroundPainter); + + mZeroBorder.SetBorderStyle(NS_SIDE_TOP, NS_STYLE_BORDER_STYLE_SOLID); + mZeroBorder.SetBorderStyle(NS_SIDE_RIGHT, NS_STYLE_BORDER_STYLE_SOLID); + mZeroBorder.SetBorderStyle(NS_SIDE_BOTTOM, NS_STYLE_BORDER_STYLE_SOLID); + mZeroBorder.SetBorderStyle(NS_SIDE_LEFT, NS_STYLE_BORDER_STYLE_SOLID); + nsStyleCoord coord(0); + mZeroBorder.mBorder.SetTop(coord); + mZeroBorder.mBorder.SetRight(coord); + mZeroBorder.mBorder.SetBottom(coord); + mZeroBorder.mBorder.SetLeft(coord); + mZeroBorder.RecalcData(); + + mZeroPadding.RecalcData(); + + mPresContext->GetScaledPixelsToTwips(&mP2t); + mIsBorderCollapse = aTableFrame->IsBorderCollapse(); +#ifdef DEBUG + mCompatMode = mPresContext->CompatibilityMode(); +#endif + mNumCols = aTableFrame->GetColCount(); +} + +TableBackgroundPainter::~TableBackgroundPainter() +{ + if (mCols) { + TableBackgroundData* lastColGroup = nsnull; + for (PRUint32 i = 0; i < mNumCols; i++) { + if (mCols[i].mColGroup != lastColGroup) { + lastColGroup = mCols[i].mColGroup; + lastColGroup->Destroy(mPresContext); + delete lastColGroup; + } + mCols[i].mColGroup = nsnull; + mCols[i].mCol.Destroy(mPresContext); + } + delete [] mCols; + } + mRowGroup.Destroy(mPresContext); + mRow.Destroy(mPresContext); + MOZ_COUNT_DTOR(TableBackgroundPainter); +} + +nsresult +TableBackgroundPainter::PaintTableFrame(nsTableFrame* aTableFrame, + nsTableRowGroupFrame* aFirstRowGroup, + nsTableRowGroupFrame* aLastRowGroup, + nsMargin* aDeflate) +{ + NS_PRECONDITION(aTableFrame, "null frame"); + TableBackgroundData tableData; + tableData.SetFull(mPresContext, mRenderingContext, aTableFrame); + tableData.mRect.MoveTo(0,0); //using table's coords + if (aDeflate) { + 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(mP2t, tempBorder); + } + border.right = tempBorder.right; + + aLastRowGroup->GetContinuousBCBorderWidth(mP2t, tempBorder); + border.bottom = tempBorder.bottom; + + nsTableRowFrame* rowFrame = aFirstRowGroup->GetFirstRow(); + if (rowFrame) { + rowFrame->GetContinuousBCBorderWidth(mP2t, tempBorder); + border.top = tempBorder.top; + } + + border.left = aTableFrame->GetContinuousLeftBCBorderWidth(mP2t); + + 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, + *tableData.mBackground, + *tableData.mBorder, + mZeroPadding, PR_TRUE); + } + tableData.Destroy(mPresContext); + return NS_OK; +} + +void +TableBackgroundPainter::TranslateContext(nscoord aDX, + nscoord aDY) +{ + mRenderingContext.Translate(aDX, aDY); + mDirtyRect.MoveBy(-aDX, -aDY); + if (mCols) { + TableBackgroundData* lastColGroup = nsnull; + for (PRUint32 i = 0; i < mNumCols; i++) { + mCols[i].mCol.mRect.MoveBy(-aDX, -aDY); + if (lastColGroup != mCols[i].mColGroup) { + NS_ASSERTION(mCols[i].mColGroup, "colgroup data should not be null"); + mCols[i].mColGroup->mRect.MoveBy(-aDX, -aDY); + lastColGroup = mCols[i].mColGroup; + } + } + } +} + +nsresult +TableBackgroundPainter::QuirksPaintTable(nsTableFrame* aTableFrame, + nsMargin& aDeflate) +{ + NS_PRECONDITION(aTableFrame, "null table frame"); + NS_PRECONDITION(eCompatibility_NavQuirks == mCompatMode, + "QuirksPaintTable called for non-Quirks"); + + nsVoidArray rowGroups; + PRUint32 numRowGroups; + aTableFrame->OrderRowGroups(rowGroups, numRowGroups); + + if (numRowGroups < 1) { //degenerate case + PaintTableFrame(aTableFrame,nsnull, nsnull, &aDeflate); + /* No cells; nothing else to paint */ + return NS_OK; + } + + PaintTableFrame(aTableFrame, + aTableFrame->GetRowGroupFrame(NS_STATIC_CAST(nsIFrame*, rowGroups.ElementAt(0))), + aTableFrame->GetRowGroupFrame(NS_STATIC_CAST(nsIFrame*, rowGroups.ElementAt(numRowGroups - 1))), + &aDeflate); + + if (mIsBorderCollapse) { + /* This is a simple pass, so we'll just keep with the table coord system. */ + + for (PRUint32 i = 0; i < numRowGroups; i++) { + nsTableRowGroupFrame* rg = aTableFrame->GetRowGroupFrame(NS_STATIC_CAST(nsIFrame*, rowGroups.ElementAt(i))); + nsRect rgRect = rg->GetRect(); + if (rgRect.Intersects(mDirtyRect) && !rg->HasView()) { + for (nsTableRowFrame* row = rg->GetFirstRow(); row; row = row->GetNextRow()) { + nsRect rowRect = row->GetRect(); + rowRect.MoveBy(rgRect.x, rgRect.y); + if (mDirtyRect.YMost() > rowRect.y && //Intersect won't handle rowspans + !row->HasView()) { + for (nsTableCellFrame* cell = row->GetFirstCell(); cell; cell = cell->GetNextCell()) { + mCellRect = cell->GetRect(); + mCellRect.MoveBy(rowRect.x, rowRect.y); + if (mCellRect.Intersects(mDirtyRect) && !cell->HasView()) { + nsresult rv = PaintCell(cell, PR_FALSE); + if (NS_FAILED(rv)) return rv; + } + } + } + } + } + } + } + return NS_OK; +} + +nsresult +TableBackgroundPainter::PaintTable(nsTableFrame* aTableFrame) +{ + NS_PRECONDITION(aTableFrame, "null table frame"); + NS_PRECONDITION(eCompatibility_NavQuirks != mCompatMode, + "must call QuirksPaintTable in Quirks mode, not PaintTable"); + + nsVoidArray rowGroups; + PRUint32 numRowGroups; + aTableFrame->OrderRowGroups(rowGroups, numRowGroups); + + if (numRowGroups < 1) { //degenerate case + PaintTableFrame(aTableFrame,nsnull, nsnull, nsnull); + /* No cells; nothing else to paint */ + return NS_OK; + } + + PaintTableFrame(aTableFrame, + aTableFrame->GetRowGroupFrame(NS_STATIC_CAST(nsIFrame*, rowGroups.ElementAt(0))), + aTableFrame->GetRowGroupFrame(NS_STATIC_CAST(nsIFrame*, rowGroups.ElementAt(numRowGroups - 1))), + nsnull); + + /*Set up column background/border data*/ + if (mNumCols > 0) { + nsFrameList& colGroupList = aTableFrame->GetColGroups(); + NS_ASSERTION(colGroupList.FirstChild(), "table should have at least one colgroup"); + + mCols = new ColData[mNumCols]; + if (!mCols) return NS_ERROR_OUT_OF_MEMORY; + + TableBackgroundData* cgData = nsnull; + nsMargin border; + /* BC left borders aren't stored on cols, but the previous column's + right border is the next one's left border.*/ + //Start with table's left border. + nscoord lastLeftBorder = aTableFrame->GetContinuousLeftBCBorderWidth(mP2t); + for (nsTableColGroupFrame* cgFrame = NS_STATIC_CAST(nsTableColGroupFrame*, colGroupList.FirstChild()); + cgFrame; cgFrame = NS_STATIC_CAST(nsTableColGroupFrame*, cgFrame->GetNextSibling())) { + + if (cgFrame->GetColCount() < 1) { + //No columns, no cells, so no need for data + continue; + } + + /*Create data struct for column group*/ + cgData = new TableBackgroundData; + if (!cgData) return NS_ERROR_OUT_OF_MEMORY; + cgData->SetFull(mPresContext, mRenderingContext, cgFrame); + if (mIsBorderCollapse && cgData->ShouldSetBCBorder()) { + border.left = lastLeftBorder; + cgFrame->GetContinuousBCBorderWidth(mP2t, border); + nsresult rv = cgData->SetBCBorder(border, this); + if (NS_FAILED(rv)) { + cgData->Destroy(mPresContext); + delete cgData; + return rv; + } + } + + /*Loop over columns in this colgroup*/ + if (cgData->IsVisible()) { + for (nsTableColFrame* col = cgFrame->GetFirstColumn(); col; + col = NS_STATIC_CAST(nsTableColFrame*, col->GetNextSibling())) { + /*Create data struct for column*/ + PRUint32 colIndex = col->GetColIndex(); + mCols[colIndex].mCol.SetFull(mPresContext, mRenderingContext, col); + //Bring column mRect into table's coord system + mCols[colIndex].mCol.mRect.MoveBy(cgData->mRect.x, cgData->mRect.y); + //link to parent colgroup's data + mCols[colIndex].mColGroup = cgData; + if (mIsBorderCollapse) { + border.left = lastLeftBorder; + lastLeftBorder = col->GetContinuousBCBorderWidth(mP2t, border); + if (mCols[colIndex].mCol.ShouldSetBCBorder()) { + nsresult rv = mCols[colIndex].mCol.SetBCBorder(border, this); + if (NS_FAILED(rv)) return rv; + } + mCols[colIndex].mCol.mBorder->GetBorder(border); + } + } + } + } + } + + for (PRUint32 i = 0; i < numRowGroups; i++) { + nsTableRowGroupFrame* rg = nsTableFrame::GetRowGroupFrame(NS_STATIC_CAST(nsIFrame*, rowGroups.ElementAt(i))); + nsRect rgRect = rg->GetRect(); + if (rgRect.Intersects(mDirtyRect)) { + nsresult rv = PaintRowGroup(rg, rg->HasView()); + if (NS_FAILED(rv)) return rv; + } + } + return NS_OK; +} + +nsresult +TableBackgroundPainter::PaintRowGroup(nsTableRowGroupFrame* aFrame, + PRBool aPassThrough) +{ + NS_PRECONDITION(aFrame, "null frame"); + NS_PRECONDITION(eCompatibility_NavQuirks != mCompatMode, + "must not call PaintRowGroup in Quirks mode"); + + nsTableRowFrame* firstRow = aFrame->GetFirstRow(); + + /* Load row group data */ + if (!aPassThrough) { + mRowGroup.SetFull(mPresContext, mRenderingContext, aFrame); + if (mIsBorderCollapse && mRowGroup.ShouldSetBCBorder()) { + nsMargin border; + if (firstRow) { + //pick up first row's top border (= rg top border) + firstRow->GetContinuousBCBorderWidth(mP2t, border); + /* (row group doesn't store its top border) */ + } + //overwrite sides+bottom borders with rg's own + aFrame->GetContinuousBCBorderWidth(mP2t, border); + nsresult res = mRowGroup.SetBCBorder(border, this); + if (!NS_SUCCEEDED(res)) { + return res; + } + } + aPassThrough = !mRowGroup.IsVisible(); + } + else { + mRowGroup.SetFrame(aFrame); + } + + /* translate everything into row group coord system*/ + if (eOrigin_TableRowGroup != mOrigin) { + TranslateContext(mRowGroup.mRect.x, mRowGroup.mRect.y); + } + nsRect rgRect = mRowGroup.mRect; + mRowGroup.mRect.MoveTo(0, 0); + + /* paint */ + for (nsTableRowFrame* row = firstRow; row; row = row->GetNextRow()) { + nsRect rect = row->GetRect(); + if (mDirtyRect.YMost() >= rect.y) { //Intersect wouldn't handle rowspans + nsresult rv = PaintRow(row, aPassThrough || row->HasView()); + if (NS_FAILED(rv)) return rv; + } + } + + /* translate back into table coord system */ + if (eOrigin_TableRowGroup != mOrigin) { + TranslateContext(-rgRect.x, -rgRect.y); + } + + /* unload rg data */ + mRowGroup.Clear(); + + return NS_OK; +} + +nsresult +TableBackgroundPainter::PaintRow(nsTableRowFrame* aFrame, + PRBool aPassThrough) +{ + NS_PRECONDITION(aFrame, "null frame"); + NS_PRECONDITION(eCompatibility_NavQuirks != mCompatMode, + "must not call PaintRow in Quirks mode"); + /* Load row data */ + if (!aPassThrough) { + mRow.SetFull(mPresContext, mRenderingContext, aFrame); + if (mIsBorderCollapse && mRow.ShouldSetBCBorder()) { + nsMargin border; + nsTableRowFrame* nextRow = aFrame->GetNextRow(); + if (nextRow) { //outer top below us is inner bottom for us + border.bottom = nextRow->GetOuterTopContBCBorderWidth(mP2t); + } + else { //acquire rg's bottom border + nsTableRowGroupFrame* rowGroup = NS_STATIC_CAST(nsTableRowGroupFrame*, aFrame->GetParent()); + rowGroup->GetContinuousBCBorderWidth(mP2t, border); + } + //get the rest of the borders; will overwrite all but bottom + aFrame->GetContinuousBCBorderWidth(mP2t, border); + + nsresult res = mRow.SetBCBorder(border, this); + if (!NS_SUCCEEDED(res)) { + return res; + } + } + aPassThrough = !mRow.IsVisible(); + } + else { + mRow.SetFrame(aFrame); + } + + /* Translate */ + if (eOrigin_TableRow == mOrigin) { + /* If we originate from the row, then make the row the origin. */ + mRow.mRect.MoveTo(0, 0); + } + //else: Use row group's coord system -> no translation necessary + + for (nsTableCellFrame* cell = aFrame->GetFirstCell(); cell; cell = cell->GetNextCell()) { + mCellRect = cell->GetRect(); + //Translate to use the same coord system as mRow. + mCellRect.MoveBy(mRow.mRect.x, mRow.mRect.y); + if (mCellRect.Intersects(mDirtyRect)) { + nsresult rv = PaintCell(cell, aPassThrough || cell->HasView()); + if (NS_FAILED(rv)) return rv; + } + } + + /* Unload row data */ + mRow.Clear(); + return NS_OK; +} + +nsresult +TableBackgroundPainter::PaintCell(nsTableCellFrame* aCell, + PRBool aPassSelf) +{ + NS_PRECONDITION(aCell, "null frame"); + + const nsStyleTableBorder* cellTableStyle; + cellTableStyle = aCell->GetStyleTableBorder(); + if (!(NS_STYLE_TABLE_EMPTY_CELLS_SHOW == cellTableStyle->mEmptyCells || + NS_STYLE_TABLE_EMPTY_CELLS_SHOW_BACKGROUND == cellTableStyle->mEmptyCells) + && aCell->GetContentEmpty()) { + return NS_OK; + } + + PRInt32 colIndex; + aCell->GetColIndex(colIndex); + + //Paint column group background + if (mCols && mCols[colIndex].mColGroup && mCols[colIndex].mColGroup->IsVisible()) { + nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext, + mCols[colIndex].mColGroup->mFrame, mDirtyRect, + mCols[colIndex].mColGroup->mRect, + *mCols[colIndex].mColGroup->mBackground, + *mCols[colIndex].mColGroup->mBorder, + mZeroPadding, PR_TRUE, &mCellRect); + } + + //Paint column background + if (mCols && mCols[colIndex].mCol.IsVisible()) { + nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext, + mCols[colIndex].mCol.mFrame, mDirtyRect, + mCols[colIndex].mCol.mRect, + *mCols[colIndex].mCol.mBackground, + *mCols[colIndex].mCol.mBorder, + mZeroPadding, PR_TRUE, &mCellRect); + } + + //Paint row group background + if (mRowGroup.IsVisible()) { + nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext, + mRowGroup.mFrame, mDirtyRect, mRowGroup.mRect, + *mRowGroup.mBackground, *mRowGroup.mBorder, + mZeroPadding, PR_TRUE, &mCellRect); + } + + //Paint row background + if (mRow.IsVisible()) { + nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext, + mRow.mFrame, mDirtyRect, mRow.mRect, + *mRow.mBackground, *mRow.mBorder, + mZeroPadding, PR_TRUE, &mCellRect); + } + + //Paint cell background in border-collapse unless we're just passing + if (mIsBorderCollapse && !aPassSelf) { + mRenderingContext.PushState(); + mRenderingContext.Translate(mCellRect.x, mCellRect.y); + mDirtyRect.MoveBy(-mCellRect.x, -mCellRect.y); + aCell->Paint(mPresContext, mRenderingContext, mDirtyRect, + NS_FRAME_PAINT_LAYER_BACKGROUND, + NS_PAINT_FLAG_TABLE_BG_PAINT | NS_PAINT_FLAG_TABLE_CELL_BG_PASS); + mDirtyRect.MoveBy(mCellRect.x, mCellRect.y); + PRBool clipEmpty; + mRenderingContext.PopState(clipEmpty); + } + + return NS_OK; +} diff --git a/mozilla/layout/tables/nsTablePainter.h b/mozilla/layout/tables/nsTablePainter.h new file mode 100644 index 00000000000..285694b1bb6 --- /dev/null +++ b/mozilla/layout/tables/nsTablePainter.h @@ -0,0 +1,271 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is TableBackgroundPainter interface. + * + * The Initial Developer of the Original Code is + * Elika J. Etemad ("fantasai") . + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsTablePainter_h__ +#define nsTablePainter_h__ + +typedef PRUint8 BCPixelSize; + +#define BC_BORDER_TOP_HALF_COORD(p2t,px) NSToCoordRound(((px) - (px) / 2) * (p2t) ) +#define BC_BORDER_RIGHT_HALF_COORD(p2t,px) NSToCoordRound(( (px) / 2) * (p2t) ) +#define BC_BORDER_BOTTOM_HALF_COORD(p2t,px) NSToCoordRound(( (px) / 2) * (p2t) ) +#define BC_BORDER_LEFT_HALF_COORD(p2t,px) NSToCoordRound(((px) - (px) / 2) * (p2t) ) + +#define BC_BORDER_TOP_HALF(px) ((px) - (px) / 2) +#define BC_BORDER_RIGHT_HALF(px) ((px) / 2) +#define BC_BORDER_BOTTOM_HALF(px) ((px) / 2) +#define BC_BORDER_LEFT_HALF(px) ((px) - (px) / 2) + +// flags for Paint, PaintChild, PaintChildren are currently only used by tables. +//Table-based paint call; not a direct call as with views +#define NS_PAINT_FLAG_TABLE_BG_PAINT 0x00000001 +//Cells should paint their backgrounds only, no children +#define NS_PAINT_FLAG_TABLE_CELL_BG_PASS 0x00000002 + +#include "nsIFrame.h" +class nsTableFrame; +class nsTableRowGroupFrame; +class nsTableRowFrame; +class nsTableCellFrame; + +class TableBackgroundPainter +{ + /* + * Helper class for painting table backgrounds + * + */ + + public: + + enum Origin { eOrigin_Table, eOrigin_TableRowGroup, eOrigin_TableRow }; + + /** Public constructor + * @param aTableFrame - the table's table frame + * @param aOrigin - what type of table frame is creating this instance + * @param aPresContext - the presentation context + * @param aRenderingContext - the rendering context + * @param aDirtyRect - the area that needs to be painted + */ + TableBackgroundPainter(nsTableFrame* aTableFrame, + Origin aOrigin, + nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + + /** Destructor */ + ~TableBackgroundPainter(); + + /* ~*~ The Border Collapse Painting Issue ~*~ + + In border-collapse, the *table* paints the cells' borders, + so we need to make sure the backgrounds get painted first + (underneath) by doing a cell-background-only painting pass. + This happens in both Standards and Quirks mode PaintTable + calls. + The table must then do a no-cell-background pass that + continues as a normal background paint call in the cell + descendants.) This method doesn't handle views very well, but + then, nothing about BC table painting really does. + */ + + /* ~*~ Using Standards Mode Painting ~*~ + + A call to PaintTable will normally paint all of the table's + elements (except the cells in non-BC). Elements with views + however, will be skipped and must create their own painter + to call the appropriate paint function in their ::Paint + method (e.g. painter.PaintRow in nsTableRow::Paint) + */ + + /** Paint background for the table frame and its children down through cells + * (Cells themselves will only be painted in border collapse) + * Standards mode only + * Table must do a flagged TABLE_BG_PAINT ::Paint call on its + * children afterwards + * @param aTableFrame - the table frame + */ + nsresult PaintTable(nsTableFrame* aTableFrame); + + /** Paint background for the row group and its children down through cells + * (Cells themselves will only be painted in border collapse) + * Standards mode only + * Table Row Group must do a flagged TABLE_BG_PAINT ::Paint call on its + * children afterwards + * @param aFrame - the table row group frame + */ + nsresult PaintRowGroup(nsTableRowGroupFrame* aFrame) + { return PaintRowGroup(aFrame, PR_FALSE); } + + /** Paint background for the row and its children down through cells + * (Cells themselves will only be painted in border collapse) + * Standards mode only + * Table Row must do a flagged TABLE_BG_PAINT ::Paint call on its + * children afterwards + * @param aFrame - the table row frame + */ + nsresult PaintRow(nsTableRowFrame* aFrame) + { return PaintRow(aFrame, PR_FALSE); } + + + /** Paint table's background, Quirks mode only + * Cell backgrounds will also be painted in border collapse: + * Table must do a flagged TABLE_BG_PAINT on its children + * afterwards. + * @param aTableFrame - the table frame + * @param aDeflate - deflation needed to bring table's mRect + * to the outer grid lines in border-collapse + */ + nsresult QuirksPaintTable(nsTableFrame* aTableFrame, + nsMargin& aDeflate); + + private: + + /** Paint table frame's background + * @param aTableFrame - the table frame + * @param aFirstRowGroup - the first (in layout order) row group + * may be null + * @param aLastRowGroup - the last (in layout order) row group + * may be null + * @param aDeflate - adjustment to frame's rect (used for quirks BC) + * may be null + */ + nsresult PaintTableFrame(nsTableFrame* aTableFrame, + nsTableRowGroupFrame* aFirstRowGroup, + nsTableRowGroupFrame* aLastRowGroup, + nsMargin* aDeflate = nsnull); + + /* aPassThrough params indicate whether to paint the element or to just + * pass through and paint underlying layers only + * See Public versions for function descriptions + */ + nsresult PaintRowGroup(nsTableRowGroupFrame* aFrame, + PRBool aPassThrough); + nsresult PaintRow(nsTableRowFrame* aFrame, + PRBool aPassThrough); + + /** Paint table background layers for this cell space + * Also paints cell's own background in border-collapse mode + * @param aFrame - the cell + * @param aPassSelf - pass this cell; i.e. paint only underlying layers + */ + nsresult PaintCell(nsTableCellFrame* aFrame, + PRBool aPassSelf); + + /** Translate mRenderingContext, mDirtyRect, and mCols' column and + * colgroup coords + * @param aDX - origin's x-coord change + * @param aDY - origin's y-coord change + */ + void TranslateContext(nscoord aDX, + nscoord aDY); + + struct TableBackgroundData; + friend struct TableBackgroundData; + MOZ_DECL_CTOR_COUNTER(TableBackgroundData) + struct TableBackgroundData { + nsIFrame* mFrame; + nsRect mRect; + const nsStyleBackground* mBackground; + const nsStyleBorder* mBorder; + + /** Data is valid & frame is visible */ + PRBool IsVisible() const { return mBackground != nsnull; } + + /** Constructor */ + TableBackgroundData(); + /** Destructor */ + ~TableBackgroundData(); + /** Destroys synthesized data. MUST be called before destructor + * @param aPresContext - the pres context + */ + void Destroy(nsIPresContext* aPresContext); + + + /** Clear background data */ + void Clear(); + + /** Calculate and set all data values to represent aFrame */ + void SetFull(nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + nsIFrame* aFrame); + + /** Set frame data (mFrame, mRect) but leave style data empty */ + void SetFrame(nsIFrame* aFrame); + + /** True if need to set border-collapse border; must call SetFull beforehand */ + PRBool ShouldSetBCBorder(); + + /** Set border-collapse border with aBorderWidth as widths */ + nsresult SetBCBorder(nsMargin& aBorderWidth, + TableBackgroundPainter* aPainter); + + private: + nsStyleBorder* mSynthBorder; + }; + + struct ColData { + TableBackgroundData mCol; + TableBackgroundData* mColGroup; //link to col's parent colgroup's data (owned by painter) + ColData() { + mColGroup = nsnull; + } + }; + + nsIPresContext* mPresContext; + nsIRenderingContext& mRenderingContext; + nsRect mDirtyRect; +#ifdef DEBUG + nsCompatibility mCompatMode; +#endif + PRBool mIsBorderCollapse; + Origin mOrigin; //user's table frame type + + ColData* mCols; //array of columns' ColData + PRUint32 mNumCols; + TableBackgroundData mRowGroup; //current row group + TableBackgroundData mRow; //current row + nsRect mCellRect; //current cell's rect + + + nsStyleBorder mZeroBorder; //cached zero-width border + nsStylePadding mZeroPadding; //cached zero-width padding + float mP2t; //pixels to twips + +}; +MOZ_DECL_CTOR_COUNTER(TableBackgroundPainter) + +#endif diff --git a/mozilla/layout/tables/nsTableRowFrame.cpp b/mozilla/layout/tables/nsTableRowFrame.cpp index 1670119d6c8..8a007e50c66 100644 --- a/mozilla/layout/tables/nsTableRowFrame.cpp +++ b/mozilla/layout/tables/nsTableRowFrame.cpp @@ -538,7 +538,25 @@ NS_METHOD nsTableRowFrame::Paint(nsIPresContext* aPresContext, aRenderingContext.DrawRect(0, 0, mRect.width, mRect.height); } #endif - // Standards mode background painting removed. See bug 4510 + + if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer && + //direct (not table-called) background paint + !(aFlags & (NS_PAINT_FLAG_TABLE_BG_PAINT | NS_PAINT_FLAG_TABLE_CELL_BG_PASS))) { + //Quirks inherits bg into cells & paints them there + if (eCompatibility_NavQuirks != aPresContext->CompatibilityMode()) { + nsTableFrame* tableFrame; + nsTableFrame::GetTableFrame(this, tableFrame); + NS_ASSERTION(tableFrame, "null table frame"); + + TableBackgroundPainter painter(tableFrame, + TableBackgroundPainter::eOrigin_TableRow, + aPresContext, aRenderingContext, + aDirtyRect); + nsresult rv = painter.PaintRow(this); + if (NS_FAILED(rv)) return rv; + aFlags |= NS_PAINT_FLAG_TABLE_BG_PAINT; + } + } PRUint8 overflow = GetStyleDisplay()->mOverflow; PRBool clip = overflow == NS_STYLE_OVERFLOW_HIDDEN || @@ -547,7 +565,8 @@ NS_METHOD nsTableRowFrame::Paint(nsIPresContext* aPresContext, aRenderingContext.PushState(); SetOverflowClipRect(aRenderingContext); } - PaintChildren(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer, aFlags); + PaintChildren(aPresContext, aRenderingContext, aDirtyRect, + aWhichLayer, aFlags); if (clip) { PRBool clipState; aRenderingContext.PopState(clipState); @@ -862,8 +881,7 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext, PRInt32 cellColIndex; cellFrame->GetColIndex(cellColIndex); cellColSpan = aTableFrame.GetEffectiveColSpan(*cellFrame); - - x += cellSpacingX; + // If the adjacent cell is in a prior row (because of a rowspan) add in the space if ((iter.IsLeftToRight() && (prevColIndex != (cellColIndex - 1))) || (!iter.IsLeftToRight() && (prevColIndex != cellColIndex + cellColSpan))) { @@ -1034,10 +1052,7 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext, } ConsiderChildOverflow(aPresContext, aDesiredSize.mOverflowArea, kidFrame); kidFrame = iter.Next(); // Get the next child - // if this was the last child, and it had a colspan>1, add in the cellSpacing for the colspan - // if the last kid wasn't a colspan, then we still have the colspan of the last real cell - if (!kidFrame && (cellColSpan > 1)) - x += cellSpacingX; + x += cellSpacingX; } // just set our width to what was available. The table will calculate the width and not use our value. @@ -1524,6 +1539,24 @@ nsTableRowFrame::GetUnpaginatedHeight(nsIPresContext* aPresContext) return 0; } +void nsTableRowFrame::SetContinuousBCBorderWidth(PRUint8 aForSide, + BCPixelSize aPixelValue) +{ + switch (aForSide) { + case NS_SIDE_RIGHT: + mRightContBorderWidth = aPixelValue; + return; + case NS_SIDE_TOP: + mTopContBorderWidth = aPixelValue; + return; + case NS_SIDE_LEFT: + mLeftContBorderWidth = aPixelValue; + return; + default: + NS_ERROR("invalid NS_SIDE arg"); + } +} + /* ----- global methods ----- */ nsresult diff --git a/mozilla/layout/tables/nsTableRowFrame.h b/mozilla/layout/tables/nsTableRowFrame.h index 483daabba18..b1ad3aa723f 100644 --- a/mozilla/layout/tables/nsTableRowFrame.h +++ b/mozilla/layout/tables/nsTableRowFrame.h @@ -39,6 +39,7 @@ #include "nscore.h" #include "nsHTMLContainerFrame.h" +#include "nsTablePainter.h" class nsTableFrame; class nsTableCellFrame; @@ -226,11 +227,31 @@ public: void SetUnpaginatedHeight(nsIPresContext* aPresContext, nscoord aValue); nscoord GetTopBCBorderWidth(float* aPixelsToTwips = nsnull); - void SetTopBCBorderWidth(nscoord aWidth); + void SetTopBCBorderWidth(BCPixelSize aWidth); nscoord GetBottomBCBorderWidth(float* aPixelsToTwips = nsnull); - void SetBottomBCBorderWidth(nscoord aWidth); + void SetBottomBCBorderWidth(BCPixelSize aWidth); nsMargin* GetBCBorderWidth(float aPixelsToTwips, nsMargin& aBorder); + + /** + * Gets inner border widths before collapsing with cell borders + * Caller must get bottom border from next row or from table + * GetContinuousBCBorderWidth will not overwrite aBorder.bottom + * see nsTablePainter about continuous borders + */ + void GetContinuousBCBorderWidth(float aPixelsToTwips, + nsMargin& aBorder); + /** + * @returns outer top bc border == prev row's bottom inner + */ + nscoord GetOuterTopContBCBorderWidth(float aPixelsToTwips); + /** + * Sets full border widths before collapsing with cell borders + * @param aForSide - side to set; only accepts right, left, and top + */ + void SetContinuousBCBorderWidth(PRUint8 aForSide, + BCPixelSize aPixelValue); + protected: /** protected constructor. @@ -238,7 +259,7 @@ protected: */ nsTableRowFrame(); - void InitChildReflowState(nsIPresContext& aPresContext, + void InitChildReflowState(nsIPresContext& aPresContext, const nsSize& aAvailSize, PRBool aBorderCollapse, float aPixelsToTwips, @@ -318,8 +339,11 @@ private: nscoord mMaxCellDescent; // does *not* include cells with rowspan > 1 // border widths in pixels in the collapsing border model - unsigned mTopBorderWidth:8; - unsigned mBottomBorderWidth:8; + BCPixelSize mTopBorderWidth; + BCPixelSize mBottomBorderWidth; + BCPixelSize mRightContBorderWidth; + BCPixelSize mTopContBorderWidth; + BCPixelSize mLeftContBorderWidth; #ifdef DEBUG_TABLE_REFLOW_TIMING public: @@ -433,7 +457,7 @@ inline nscoord nsTableRowFrame::GetTopBCBorderWidth(float* aPixelsToTwips) return width; } -inline void nsTableRowFrame::SetTopBCBorderWidth(nscoord aWidth) +inline void nsTableRowFrame::SetTopBCBorderWidth(BCPixelSize aWidth) { mTopBorderWidth = aWidth; } @@ -444,7 +468,7 @@ inline nscoord nsTableRowFrame::GetBottomBCBorderWidth(float* aPixelsToTwips) return width; } -inline void nsTableRowFrame::SetBottomBCBorderWidth(nscoord aWidth) +inline void nsTableRowFrame::SetBottomBCBorderWidth(BCPixelSize aWidth) { mBottomBorderWidth = aWidth; } @@ -460,4 +484,21 @@ inline nsMargin* nsTableRowFrame::GetBCBorderWidth(float aPixelsToTwips, return &aBorder; } +inline void +nsTableRowFrame::GetContinuousBCBorderWidth(float aPixelsToTwips, + nsMargin& aBorder) +{ + aBorder.right = BC_BORDER_LEFT_HALF_COORD(aPixelsToTwips, + mLeftContBorderWidth); + aBorder.top = BC_BORDER_BOTTOM_HALF_COORD(aPixelsToTwips, + mTopContBorderWidth); + aBorder.left = BC_BORDER_RIGHT_HALF_COORD(aPixelsToTwips, + mRightContBorderWidth); +} + +inline nscoord nsTableRowFrame::GetOuterTopContBCBorderWidth(float aPixelsToTwips) +{ + return BC_BORDER_TOP_HALF_COORD(aPixelsToTwips, mTopContBorderWidth); +} + #endif diff --git a/mozilla/layout/tables/nsTableRowGroupFrame.cpp b/mozilla/layout/tables/nsTableRowGroupFrame.cpp index 380dd48c24c..bfbba9e24e7 100644 --- a/mozilla/layout/tables/nsTableRowGroupFrame.cpp +++ b/mozilla/layout/tables/nsTableRowGroupFrame.cpp @@ -94,7 +94,7 @@ nsTableRowGroupFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) *aInstancePtr = (void*)this; return NS_OK; } - else if (aIID.Equals(NS_GET_IID(nsILineIteratorNavigator))) + else if (aIID.Equals(NS_GET_IID(nsILineIteratorNavigator))) { // note there is no addref here, frames are not addref'd *aInstancePtr = (void*)(nsILineIteratorNavigator*)this; return NS_OK; @@ -204,7 +204,25 @@ NS_METHOD nsTableRowGroupFrame::Paint(nsIPresContext* aPresContext, aRenderingContext.DrawRect(0, 0, mRect.width, mRect.height); } #endif - // Standards mode background painting removed. See bug 4510 + + if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer && + //direct (not table-called) background paint + !(aFlags & (NS_PAINT_FLAG_TABLE_BG_PAINT | NS_PAINT_FLAG_TABLE_CELL_BG_PASS))) { + //Quirks inherits bg into cells & paints them there + if (eCompatibility_NavQuirks != aPresContext->CompatibilityMode()) { + nsTableFrame* tableFrame; + nsTableFrame::GetTableFrame(this, tableFrame); + NS_ASSERTION(tableFrame, "null table frame"); + + TableBackgroundPainter painter(tableFrame, + TableBackgroundPainter::eOrigin_TableRowGroup, + aPresContext, aRenderingContext, + aDirtyRect); + nsresult rv = painter.PaintRowGroup(this); + if (NS_FAILED(rv)) return rv; + aFlags |= NS_PAINT_FLAG_TABLE_BG_PAINT; + } + } PRUint8 overflow = GetStyleDisplay()->mOverflow; PRBool clip = overflow == NS_STYLE_OVERFLOW_HIDDEN || @@ -213,7 +231,8 @@ NS_METHOD nsTableRowGroupFrame::Paint(nsIPresContext* aPresContext, aRenderingContext.PushState(); SetOverflowClipRect(aRenderingContext); } - PaintChildren(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer, aFlags); + PaintChildren(aPresContext, aRenderingContext, aDirtyRect, + aWhichLayer, aFlags); if (clip) { PRBool clipState; aRenderingContext.PopState(clipState); @@ -286,9 +305,9 @@ nsTableRowGroupFrame::GetFrameForPoint(nsIPresContext* aPresContext, // aKidRect is relative to the upper-left origin of our frame void nsTableRowGroupFrame::PlaceChild(nsIPresContext* aPresContext, - nsRowGroupReflowState& aReflowState, - nsIFrame* aKidFrame, - nsHTMLReflowMetrics& aDesiredSize) + nsRowGroupReflowState& aReflowState, + nsIFrame* aKidFrame, + nsHTMLReflowMetrics& aDesiredSize) { // Place and size the child FinishReflowChild(aKidFrame, aPresContext, nsnull, aDesiredSize, 0, aReflowState.y, 0); @@ -1854,6 +1873,24 @@ nsTableRowGroupFrame::GetBCBorderWidth(float aPixelsToTwips, return &aBorder; } +void nsTableRowGroupFrame::SetContinuousBCBorderWidth(PRUint8 aForSide, + BCPixelSize aPixelValue) +{ + switch (aForSide) { + case NS_SIDE_RIGHT: + mRightContBorderWidth = aPixelValue; + return; + case NS_SIDE_BOTTOM: + mBottomContBorderWidth = aPixelValue; + return; + case NS_SIDE_LEFT: + mLeftContBorderWidth = aPixelValue; + return; + default: + NS_ERROR("invalid NS_SIDE argument"); + } +} + //nsILineIterator methods for nsTableFrame NS_IMETHODIMP nsTableRowGroupFrame::GetNumLines(PRInt32* aResult) diff --git a/mozilla/layout/tables/nsTableRowGroupFrame.h b/mozilla/layout/tables/nsTableRowGroupFrame.h index bf62b14627c..d865aad1c96 100644 --- a/mozilla/layout/tables/nsTableRowGroupFrame.h +++ b/mozilla/layout/tables/nsTableRowGroupFrame.h @@ -41,6 +41,7 @@ #include "nsHTMLContainerFrame.h" #include "nsIAtom.h" #include "nsILineIterator.h" +#include "nsTablePainter.h" class nsTableFrame; class nsTableRowFrame; @@ -220,6 +221,22 @@ public: nsMargin* GetBCBorderWidth(float aPixelsToTwips, nsMargin& aBorder); + + /** + * Gets inner border widths before collapsing with cell borders + * Caller must get top border from previous row group or from table + * GetContinuousBCBorderWidth will not overwrite aBorder.top + * see nsTablePainter about continuous borders + */ + void GetContinuousBCBorderWidth(float aPixelsToTwips, + nsMargin& aBorder); + /** + * Sets full border widths before collapsing with cell borders + * @param aForSide - side to set; only right, left, and bottom valid + */ + void SetContinuousBCBorderWidth(PRUint8 aForSide, + BCPixelSize aPixelValue); + // nsILineIterator methods public: NS_IMETHOD GetNumLines(PRInt32* aResult); @@ -359,6 +376,13 @@ protected: void UndoContinuedRow(nsIPresContext* aPresContext, nsTableRowFrame* aRow); + +private: + // border widths in pixels in the collapsing border model + BCPixelSize mRightContBorderWidth; + BCPixelSize mBottomContBorderWidth; + BCPixelSize mLeftContBorderWidth; + public: virtual nsIFrame* GetFirstFrame() { return mFrames.FirstChild(); }; virtual nsIFrame* GetLastFrame() { return mFrames.LastChild(); }; @@ -419,4 +443,17 @@ inline void nsTableRowGroupFrame::SetHasStyleHeight(PRBool aValue) mState &= ~NS_ROWGROUP_HAS_STYLE_HEIGHT; } } + +inline void +nsTableRowGroupFrame::GetContinuousBCBorderWidth(float aPixelsToTwips, + nsMargin& aBorder) +{ + aBorder.right = BC_BORDER_LEFT_HALF_COORD(aPixelsToTwips, + mRightContBorderWidth); + aBorder.bottom = BC_BORDER_TOP_HALF_COORD(aPixelsToTwips, + mBottomContBorderWidth); + aBorder.left = BC_BORDER_RIGHT_HALF_COORD(aPixelsToTwips, + mLeftContBorderWidth); + return; +} #endif