Bug 613659 - Implement box-decoration-break layout for border/box-shadow and paddding/margin for inlines. r=cam

This commit is contained in:
Mats Palmgren 2014-04-17 12:11:07 +00:00
parent 1f9f1cafa0
commit 8fca6e72ff
15 changed files with 387 additions and 122 deletions

View File

@ -61,6 +61,19 @@ using mozilla::CSSSizeOrRatio;
static int gFrameTreeLockCount = 0; static int gFrameTreeLockCount = 0;
static void
ApplySkipSides(int aSkipSides, nsMargin* aMargin)
{
if (aSkipSides & SIDE_BIT_LEFT)
aMargin->left = 0;
if (aSkipSides & SIDE_BIT_TOP)
aMargin->top = 0;
if (aSkipSides & SIDE_BIT_RIGHT)
aMargin->right = 0;
if (aSkipSides & SIDE_BIT_BOTTOM)
aMargin->bottom = 0;
}
// To avoid storing this data on nsInlineFrame (bloat) and to avoid // To avoid storing this data on nsInlineFrame (bloat) and to avoid
// recalculating this for each frame in a continuation (perf), hold // recalculating this for each frame in a continuation (perf), hold
// a cache of various coordinate information that we need in order // a cache of various coordinate information that we need in order
@ -81,10 +94,18 @@ struct InlineBackgroundData
mBoundingBox.SetRect(0,0,0,0); mBoundingBox.SetRect(0,0,0,0);
mContinuationPoint = mLineContinuationPoint = mUnbrokenWidth = 0; mContinuationPoint = mLineContinuationPoint = mUnbrokenWidth = 0;
mFrame = mBlockFrame = nullptr; mFrame = mBlockFrame = nullptr;
mLeftBorderData.Reset();
} }
/**
* Return a continuous rect for (an inline) aFrame relative to the
* continuation that draws the left-most part of the background.
* This is used when painting backgrounds.
*/
nsRect GetContinuousRect(nsIFrame* aFrame) nsRect GetContinuousRect(nsIFrame* aFrame)
{ {
MOZ_ASSERT(aFrame->GetType() == nsGkAtoms::inlineFrame);
SetFrame(aFrame); SetFrame(aFrame);
nscoord x; nscoord x;
@ -98,12 +119,9 @@ struct InlineBackgroundData
NS_STYLE_DIRECTION_RTL); NS_STYLE_DIRECTION_RTL);
nscoord curOffset = aFrame->GetOffsetTo(mBlockFrame).x; nscoord curOffset = aFrame->GetOffsetTo(mBlockFrame).x;
// No need to use our GetPrevContinuation/GetNextContinuation methods
// here, since ib-split siblings are certainly not on the same line.
nsIFrame* inlineFrame = aFrame->GetPrevContinuation();
// If the continuation is fluid we know inlineFrame is not on the same line. // If the continuation is fluid we know inlineFrame is not on the same line.
// If it's not fluid, we need to test further to be sure. // If it's not fluid, we need to test further to be sure.
nsIFrame* inlineFrame = aFrame->GetPrevContinuation();
while (inlineFrame && !inlineFrame->GetNextInFlow() && while (inlineFrame && !inlineFrame->GetNextInFlow() &&
AreOnSameLine(aFrame, inlineFrame)) { AreOnSameLine(aFrame, inlineFrame)) {
nscoord frameXOffset = inlineFrame->GetOffsetTo(mBlockFrame).x; nscoord frameXOffset = inlineFrame->GetOffsetTo(mBlockFrame).x;
@ -140,6 +158,39 @@ struct InlineBackgroundData
return nsRect(-x, 0, mUnbrokenWidth, mFrame->GetSize().height); return nsRect(-x, 0, mUnbrokenWidth, mFrame->GetSize().height);
} }
/**
* Return a continuous rect for (an inline) aFrame relative to the
* continuation that should draw the left-border. This is used when painting
* borders and clipping backgrounds. This may NOT be the same continuous rect
* as for drawing backgrounds; the continuation with the left-border might be
* somewhere in the middle of that rect (e.g. BIDI), in those cases we need
* the reverse background order starting at the left-border continuation.
*/
nsRect GetBorderContinuousRect(nsIFrame* aFrame, nsRect aBorderArea)
{
// Calling GetContinuousRect(aFrame) here may lead to Reset/Init which
// resets our mLeftBorderData so we save it ...
LeftBorderData saved(mLeftBorderData);
nsRect joinedBorderArea = GetContinuousRect(aFrame);
if (!saved.mIsValid || saved.mFrame != mLeftBorderData.mFrame) {
if (aFrame == mLeftBorderData.mFrame) {
mLeftBorderData.SetX(joinedBorderArea.x);
} else if (mLeftBorderData.mFrame) {
mLeftBorderData.SetX(GetContinuousRect(mLeftBorderData.mFrame).x);
}
} else {
// ... and restore it when possible.
mLeftBorderData.mX = saved.mX;
}
if (joinedBorderArea.x > mLeftBorderData.mX) {
joinedBorderArea.x =
-(mUnbrokenWidth + joinedBorderArea.x - aBorderArea.width);
} else {
joinedBorderArea.x -= mLeftBorderData.mX;
}
return joinedBorderArea;
}
nsRect GetBoundingRect(nsIFrame* aFrame) nsRect GetBoundingRect(nsIFrame* aFrame)
{ {
SetFrame(aFrame); SetFrame(aFrame);
@ -157,13 +208,22 @@ struct InlineBackgroundData
} }
protected: protected:
nsIFrame* mFrame; struct LeftBorderData {
nsBlockFrame* mBlockFrame; nsIFrame* mFrame; // the continuation that may have a left-border
nsRect mBoundingBox; nscoord mX; // cached GetContinuousRect(mFrame).x
nscoord mContinuationPoint; bool mIsValid; // true if mX is valid
nscoord mUnbrokenWidth; void Reset() { mFrame = nullptr; mIsValid = false; }
nscoord mLineContinuationPoint; void SetX(nscoord aX) { mX = aX; mIsValid = true; }
bool mBidiEnabled; };
nsIFrame* mFrame;
nsBlockFrame* mBlockFrame;
nsRect mBoundingBox;
nscoord mContinuationPoint;
nscoord mUnbrokenWidth;
nscoord mLineContinuationPoint;
LeftBorderData mLeftBorderData;
bool mBidiEnabled;
void SetFrame(nsIFrame* aFrame) void SetFrame(nsIFrame* aFrame)
{ {
@ -236,6 +296,7 @@ protected:
void Init(nsIFrame* aFrame) void Init(nsIFrame* aFrame)
{ {
mLeftBorderData.Reset();
mBidiEnabled = aFrame->PresContext()->BidiEnabled(); mBidiEnabled = aFrame->PresContext()->BidiEnabled();
if (mBidiEnabled) { if (mBidiEnabled) {
// Find the containing block frame // Find the containing block frame
@ -252,8 +313,11 @@ protected:
// Start with the previous flow frame as our continuation point // Start with the previous flow frame as our continuation point
// is the total of the widths of the previous frames. // is the total of the widths of the previous frames.
nsIFrame* inlineFrame = GetPrevContinuation(aFrame); nsIFrame* inlineFrame = GetPrevContinuation(aFrame);
while (inlineFrame) { while (inlineFrame) {
if (!mLeftBorderData.mFrame &&
!(inlineFrame->GetSkipSides() & SIDE_BIT_LEFT)) {
mLeftBorderData.mFrame = inlineFrame;
}
nsRect rect = inlineFrame->GetRect(); nsRect rect = inlineFrame->GetRect();
mContinuationPoint += rect.width; mContinuationPoint += rect.width;
if (mBidiEnabled && !AreOnSameLine(aFrame, inlineFrame)) { if (mBidiEnabled && !AreOnSameLine(aFrame, inlineFrame)) {
@ -268,6 +332,10 @@ protected:
// unbroken width. // unbroken width.
inlineFrame = aFrame; inlineFrame = aFrame;
while (inlineFrame) { while (inlineFrame) {
if (!mLeftBorderData.mFrame &&
!(inlineFrame->GetSkipSides() & SIDE_BIT_LEFT)) {
mLeftBorderData.mFrame = inlineFrame;
}
nsRect rect = inlineFrame->GetRect(); nsRect rect = inlineFrame->GetRect();
mUnbrokenWidth += rect.width; mUnbrokenWidth += rect.width;
mBoundingBox.UnionRect(mBoundingBox, rect); mBoundingBox.UnionRect(mBoundingBox, rect);
@ -371,6 +439,94 @@ MakeBevelColor(mozilla::css::Side whichSide, uint8_t style,
return theColor; return theColor;
} }
static bool
GetRadii(nsIFrame* aForFrame, const nsStyleBorder& aBorder,
const nsRect& aOrigBorderArea, const nsRect& aBorderArea,
gfxCornerSizes* aBgRadii)
{
nscoord radii[8];
bool haveRoundedCorners;
nsSize sz = aBorderArea.Size();
nsSize frameSize = aForFrame->GetSize();
if (&aBorder == aForFrame->StyleBorder() &&
frameSize == aOrigBorderArea.Size()) {
haveRoundedCorners = aForFrame->GetBorderRadii(sz, sz, 0, radii);
} else {
haveRoundedCorners =
nsIFrame::ComputeBorderRadii(aBorder.mBorderRadius, frameSize, sz, 0, radii);
}
if (haveRoundedCorners) {
auto d2a = aForFrame->PresContext()->AppUnitsPerDevPixel();
nsCSSRendering::ComputePixelRadii(radii, d2a, aBgRadii);
}
return haveRoundedCorners;
}
static nsRect
JoinBoxesForVerticalSlice(nsIFrame* aFrame, const nsRect& aBorderArea)
{
// Inflate vertically as if our continuations were laid out vertically
// adjacent. Note that we don't touch the width.
nsRect borderArea = aBorderArea;
nscoord h = 0;
nsIFrame* f = aFrame->GetNextContinuation();
for (; f; f = f->GetNextContinuation()) {
MOZ_ASSERT(!(f->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT),
"anonymous ib-split block shouldn't have border/background");
h += f->GetRect().height;
}
borderArea.height += h;
h = 0;
f = aFrame->GetPrevContinuation();
for (; f; f = f->GetPrevContinuation()) {
MOZ_ASSERT(!(f->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT),
"anonymous ib-split block shouldn't have border/background");
h += f->GetRect().height;
}
borderArea.y -= h;
borderArea.height += h;
return borderArea;
}
/**
* Inflate aBorderArea which is relative to aFrame's origin to calculate
* a hypothetical non-split frame area for all the continuations.
* See "Joining Boxes for 'slice'" in
* http://dev.w3.org/csswg/css-break/#break-decoration
*/
enum InlineBoxOrder { eForBorder, eForBackground };
static nsRect
JoinBoxesForSlice(nsIFrame* aFrame, const nsRect& aBorderArea,
InlineBoxOrder aOrder)
{
if (aFrame->GetType() == nsGkAtoms::inlineFrame) {
return (aOrder == eForBorder
? gInlineBGData->GetBorderContinuousRect(aFrame, aBorderArea)
: gInlineBGData->GetContinuousRect(aFrame)) +
aBorderArea.TopLeft();
}
return JoinBoxesForVerticalSlice(aFrame, aBorderArea);
}
static bool
IsBoxDecorationSlice(const nsStyleBorder& aStyleBorder)
{
return aStyleBorder.mBoxDecorationBreak ==
NS_STYLE_BOX_DECORATION_BREAK_SLICE;
}
static nsRect
BoxDecorationRectForBorder(nsIFrame* aFrame, const nsRect& aBorderArea,
const nsStyleBorder* aStyleBorder = nullptr)
{
if (!aStyleBorder) {
aStyleBorder = aFrame->StyleBorder();
}
return ::IsBoxDecorationSlice(*aStyleBorder)
? ::JoinBoxesForSlice(aFrame, aBorderArea, eForBorder)
: aBorderArea;
}
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// Thebes Border Rendering Code Start // Thebes Border Rendering Code Start
@ -449,10 +605,6 @@ nsCSSRendering::PaintBorderWithStyleBorder(nsPresContext* aPresContext,
nsStyleContext* aStyleContext, nsStyleContext* aStyleContext,
int aSkipSides) int aSkipSides)
{ {
nsMargin border;
nscoord twipsRadii[8];
nsCompatibility compatMode = aPresContext->CompatibilityMode();
SN("++ PaintBorder"); SN("++ PaintBorder");
// Check to see if we have an appearance defined. If so, we let the theme // Check to see if we have an appearance defined. If so, we let the theme
@ -474,59 +626,67 @@ nsCSSRendering::PaintBorderWithStyleBorder(nsPresContext* aPresContext,
// Get our style context's color struct. // Get our style context's color struct.
const nsStyleColor* ourColor = aStyleContext->StyleColor(); const nsStyleColor* ourColor = aStyleContext->StyleColor();
// in NavQuirks mode we want to use the parent's context as a starting point // In NavQuirks mode we want to use the parent's context as a starting point
// for determining the background color // for determining the background color.
nsIFrame* bgFrame = nsCSSRendering::FindNonTransparentBackgroundFrame bool quirks = aPresContext->CompatibilityMode() == eCompatibility_NavQuirks;
(aForFrame, compatMode == eCompatibility_NavQuirks ? true : false); nsIFrame* bgFrame = FindNonTransparentBackgroundFrame(aForFrame, quirks);
nsStyleContext* bgContext = bgFrame->StyleContext(); nsStyleContext* bgContext = bgFrame->StyleContext();
nscolor bgColor = nscolor bgColor =
bgContext->GetVisitedDependentColor(eCSSProperty_background_color); bgContext->GetVisitedDependentColor(eCSSProperty_background_color);
border = aStyleBorder.GetComputedBorder(); nsMargin border = aStyleBorder.GetComputedBorder();
if ((0 == border.left) && (0 == border.right) && if ((0 == border.left) && (0 == border.right) &&
(0 == border.top) && (0 == border.bottom)) { (0 == border.top) && (0 == border.bottom)) {
// Empty border area // Empty border area
return; return;
} }
nsSize frameSize = aForFrame->GetSize(); // Compute the outermost boundary of the area that might be painted.
if (&aStyleBorder == aForFrame->StyleBorder() && // Same coordinate space as aBorderArea & aBGClipRect.
frameSize == aBorderArea.Size()) { nsRect joinedBorderArea =
aForFrame->GetBorderRadii(twipsRadii); ::BoxDecorationRectForBorder(aForFrame, aBorderArea, &aStyleBorder);
gfxCornerSizes bgRadii;
::GetRadii(aForFrame, aStyleBorder, aBorderArea, joinedBorderArea, &bgRadii);
SF(" joinedBorderArea: %d %d %d %d\n", joinedBorderArea.x, joinedBorderArea.y,
joinedBorderArea.width, joinedBorderArea.height);
// start drawing
gfxContext* ctx = aRenderingContext.ThebesContext();
ctx->Save();
if (::IsBoxDecorationSlice(aStyleBorder)) {
if (aSkipSides == 0) {
// No continuations most likely, or ::first-letter that wants all border-
// sides on the first continuation.
joinedBorderArea = aBorderArea;
} else if (joinedBorderArea.IsEqualEdges(aBorderArea)) {
// No need for a clip, just skip the sides we don't want.
::ApplySkipSides(aSkipSides, &border);
} else {
// We're drawing borders around the joined continuation boxes so we need
// to clip that to the slice that we want for this frame.
aRenderingContext.IntersectClip(aBorderArea);
}
} else { } else {
nsIFrame::ComputeBorderRadii(aStyleBorder.mBorderRadius, frameSize, MOZ_ASSERT(joinedBorderArea.IsEqualEdges(aBorderArea),
aBorderArea.Size(), aSkipSides, twipsRadii); "Should use aBorderArea for box-decoration-break:clone");
MOZ_ASSERT(aForFrame->GetSkipSides() == 0,
"Should not skip sides for box-decoration-break:clone except "
"::first-letter/line continuations or other frame types that "
"don't have borders but those shouldn't reach this point.");
} }
// Turn off rendering for all of the zero sized sides // Convert to dev pixels.
if (aSkipSides & SIDE_BIT_TOP) border.top = 0;
if (aSkipSides & SIDE_BIT_RIGHT) border.right = 0;
if (aSkipSides & SIDE_BIT_BOTTOM) border.bottom = 0;
if (aSkipSides & SIDE_BIT_LEFT) border.left = 0;
// get the inside and outside parts of the border
nsRect outerRect(aBorderArea);
SF(" outerRect: %d %d %d %d\n", outerRect.x, outerRect.y, outerRect.width, outerRect.height);
// we can assume that we're already clipped to aDirtyRect -- I think? (!?)
// Get our conversion values
nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1); nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
gfxRect joinedBorderAreaPx =
// convert outer and inner rects nsLayoutUtils::RectToGfxRect(joinedBorderArea, twipsPerPixel);
gfxRect oRect(nsLayoutUtils::RectToGfxRect(outerRect, twipsPerPixel));
// convert the border widths
gfxFloat borderWidths[4] = { gfxFloat(border.top / twipsPerPixel), gfxFloat borderWidths[4] = { gfxFloat(border.top / twipsPerPixel),
gfxFloat(border.right / twipsPerPixel), gfxFloat(border.right / twipsPerPixel),
gfxFloat(border.bottom / twipsPerPixel), gfxFloat(border.bottom / twipsPerPixel),
gfxFloat(border.left / twipsPerPixel) }; gfxFloat(border.left / twipsPerPixel) };
// convert the radii
gfxCornerSizes borderRadii;
ComputePixelRadii(twipsRadii, twipsPerPixel, &borderRadii);
uint8_t borderStyles[4]; uint8_t borderStyles[4];
nscolor borderColors[4]; nscolor borderColors[4];
nsBorderColors *compositeColors[4]; nsBorderColors *compositeColors[4];
@ -543,32 +703,25 @@ nsCSSRendering::PaintBorderWithStyleBorder(nsPresContext* aPresContext,
} }
SF(" borderStyles: %d %d %d %d\n", borderStyles[0], borderStyles[1], borderStyles[2], borderStyles[3]); SF(" borderStyles: %d %d %d %d\n", borderStyles[0], borderStyles[1], borderStyles[2], borderStyles[3]);
//SF ("bgRadii: %f %f %f %f\n", bgRadii[0], bgRadii[1], bgRadii[2], bgRadii[3]);
// start drawing
gfxContext *ctx = aRenderingContext.ThebesContext();
ctx->Save();
#if 0 #if 0
// this will draw a transparent red backround underneath the oRect area // this will draw a transparent red backround underneath the border area
ctx->Save(); ctx->Save();
ctx->Rectangle(oRect); ctx->Rectangle(joinedBorderAreaPx);
ctx->SetColor(gfxRGBA(1.0, 0.0, 0.0, 0.5)); ctx->SetColor(gfxRGBA(1.0, 0.0, 0.0, 0.5));
ctx->Fill(); ctx->Fill();
ctx->Restore(); ctx->Restore();
#endif #endif
//SF ("borderRadii: %f %f %f %f\n", borderRadii[0], borderRadii[1], borderRadii[2], borderRadii[3]);
nsCSSBorderRenderer br(twipsPerPixel, nsCSSBorderRenderer br(twipsPerPixel,
ctx, ctx,
oRect, joinedBorderAreaPx,
borderStyles, borderStyles,
borderWidths, borderWidths,
borderRadii, bgRadii,
borderColors, borderColors,
compositeColors, compositeColors,
aSkipSides,
bgColor); bgColor);
br.DrawBorders(); br.DrawBorders();
@ -688,7 +841,7 @@ nsCSSRendering::PaintOutline(nsPresContext* aPresContext,
outlineWidths, outlineWidths,
outlineRadii, outlineRadii,
outlineColors, outlineColors,
nullptr, 0, nullptr,
bgColor); bgColor);
br.DrawBorders(); br.DrawBorders();
@ -741,7 +894,7 @@ nsCSSRendering::PaintFocus(nsPresContext* aPresContext,
focusWidths, focusWidths,
focusRadii, focusRadii,
focusColors, focusColors,
nullptr, 0, nullptr,
NS_RGB(255, 0, 0)); NS_RGB(255, 0, 0));
br.DrawBorders(); br.DrawBorders();
@ -996,13 +1149,10 @@ nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
nsCSSShadowArray* shadows = styleBorder->mBoxShadow; nsCSSShadowArray* shadows = styleBorder->mBoxShadow;
if (!shadows) if (!shadows)
return; return;
nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
gfxContextAutoSaveRestore gfxStateRestorer;
bool hasBorderRadius; bool hasBorderRadius;
bool nativeTheme; // mutually exclusive with hasBorderRadius bool nativeTheme; // mutually exclusive with hasBorderRadius
gfxCornerSizes borderRadii;
// Get any border radius, since box-shadow must also have rounded corners if the frame does
const nsStyleDisplay* styleDisplay = aForFrame->StyleDisplay(); const nsStyleDisplay* styleDisplay = aForFrame->StyleDisplay();
nsITheme::Transparency transparency; nsITheme::Transparency transparency;
if (aForFrame->IsThemed(styleDisplay, &transparency)) { if (aForFrame->IsThemed(styleDisplay, &transparency)) {
@ -1013,17 +1163,29 @@ nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
nativeTheme = transparency != nsITheme::eOpaque; nativeTheme = transparency != nsITheme::eOpaque;
} else { } else {
nativeTheme = false; nativeTheme = false;
hasBorderRadius = true; // we'll update this below
}
nsRect frameRect = nativeTheme ?
aForFrame->GetVisualOverflowRectRelativeToSelf() + aFrameArea.TopLeft() :
aFrameArea;
frameRect = ::BoxDecorationRectForBorder(aForFrame, frameRect);
// Get any border radius, since box-shadow must also have rounded corners if
// the frame does.
gfxCornerSizes borderRadii;
const nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
if (hasBorderRadius) {
nscoord twipsRadii[8]; nscoord twipsRadii[8];
NS_ASSERTION(aFrameArea.Size() == aForFrame->VisualBorderRectRelativeToSelf().Size(), NS_ASSERTION(aFrameArea.Size() == aForFrame->VisualBorderRectRelativeToSelf().Size(),
"unexpected size"); "unexpected size");
hasBorderRadius = aForFrame->GetBorderRadii(twipsRadii); nsSize sz = frameRect.Size();
hasBorderRadius = aForFrame->GetBorderRadii(sz, sz, 0, twipsRadii);
if (hasBorderRadius) { if (hasBorderRadius) {
ComputePixelRadii(twipsRadii, twipsPerPixel, &borderRadii); ComputePixelRadii(twipsRadii, twipsPerPixel, &borderRadii);
} }
} }
nsRect frameRect =
nativeTheme ? aForFrame->GetVisualOverflowRectRelativeToSelf() + aFrameArea.TopLeft() : aFrameArea;
gfxRect frameGfxRect(nsLayoutUtils::RectToGfxRect(frameRect, twipsPerPixel)); gfxRect frameGfxRect(nsLayoutUtils::RectToGfxRect(frameRect, twipsPerPixel));
frameGfxRect.Round(); frameGfxRect.Round();
@ -1047,6 +1209,7 @@ nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
std::max(borderRadii[C_BL].height, borderRadii[C_BR].height), 0)); std::max(borderRadii[C_BL].height, borderRadii[C_BR].height), 0));
} }
int skipSides = aForFrame->GetSkipSides();
for (uint32_t i = shadows->Length(); i > 0; --i) { for (uint32_t i = shadows->Length(); i > 0; --i) {
nsCSSShadowItem* shadowItem = shadows->ShadowAt(i - 1); nsCSSShadowItem* shadowItem = shadows->ShadowAt(i - 1);
if (shadowItem->mInset) if (shadowItem->mInset)
@ -1127,7 +1290,7 @@ nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
} else { } else {
renderContext->Save(); renderContext->Save();
// Clip out the area of the actual frame so the shadow is not shown within // Clip out the area of the actual frame so the shadow is not shown within
// the frame // the frame.
renderContext->NewPath(); renderContext->NewPath();
renderContext->Rectangle(shadowGfxRectPlusBlur); renderContext->Rectangle(shadowGfxRectPlusBlur);
if (hasBorderRadius) { if (hasBorderRadius) {
@ -1139,6 +1302,36 @@ nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
renderContext->SetFillRule(gfxContext::FILL_RULE_EVEN_ODD); renderContext->SetFillRule(gfxContext::FILL_RULE_EVEN_ODD);
renderContext->Clip(); renderContext->Clip();
// Clip the shadow so that we only get the part that applies to aForFrame.
nsRect fragmentClip = shadowRectPlusBlur;
if (skipSides) {
if (skipSides & SIDE_BIT_LEFT) {
nscoord xmost = fragmentClip.XMost();
fragmentClip.x = aFrameArea.x;
fragmentClip.width = xmost - fragmentClip.x;
}
if (skipSides & SIDE_BIT_RIGHT) {
nscoord xmost = fragmentClip.XMost();
nscoord overflow = xmost - aFrameArea.XMost();
if (overflow > 0) {
fragmentClip.width -= overflow;
}
}
if (skipSides & SIDE_BIT_TOP) {
nscoord ymost = fragmentClip.YMost();
fragmentClip.y = aFrameArea.y;
fragmentClip.height = ymost - fragmentClip.y;
}
if (skipSides & SIDE_BIT_BOTTOM) {
nscoord ymost = fragmentClip.YMost();
nscoord overflow = ymost - aFrameArea.YMost();
if (overflow > 0) {
fragmentClip.height -= overflow;
}
}
}
aRenderingContext.IntersectClip(fragmentClip);
gfxCornerSizes clipRectRadii; gfxCornerSizes clipRectRadii;
if (hasBorderRadius) { if (hasBorderRadius) {
gfxFloat spreadDistance = shadowItem->mSpread / twipsPerPixel; gfxFloat spreadDistance = shadowItem->mSpread / twipsPerPixel;
@ -1188,18 +1381,20 @@ nsCSSRendering::PaintBoxShadowInner(nsPresContext* aPresContext,
return; return;
} }
NS_ASSERTION(aForFrame->GetType() == nsGkAtoms::fieldSetFrame ||
aFrameArea.Size() == aForFrame->GetSize(), "unexpected size");
nsRect frameRect = ::BoxDecorationRectForBorder(aForFrame, aFrameArea);
nsRect paddingRect = frameRect;
nsMargin border = aForFrame->GetUsedBorder();
paddingRect.Deflate(border);
// Get any border radius, since box-shadow must also have rounded corners // Get any border radius, since box-shadow must also have rounded corners
// if the frame does. // if the frame does.
nscoord twipsRadii[8]; nscoord twipsRadii[8];
NS_ASSERTION(aForFrame->GetType() == nsGkAtoms::fieldSetFrame || nsSize sz = frameRect.Size();
aFrameArea.Size() == aForFrame->GetSize(), "unexpected size"); bool hasBorderRadius = aForFrame->GetBorderRadii(sz, sz, 0, twipsRadii);
bool hasBorderRadius = aForFrame->GetBorderRadii(twipsRadii); const nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
nsRect paddingRect = aFrameArea;
nsMargin border = aForFrame->GetUsedBorder();
aForFrame->ApplySkipSides(border);
paddingRect.Deflate(border);
gfxCornerSizes innerRadii; gfxCornerSizes innerRadii;
if (hasBorderRadius) { if (hasBorderRadius) {
@ -1221,13 +1416,9 @@ nsCSSRendering::PaintBoxShadowInner(nsPresContext* aPresContext,
if (!shadowItem->mInset) if (!shadowItem->mInset)
continue; continue;
/* // shadowPaintRect: the area to paint on the temp surface
* shadowRect: the frame's padding rect // shadowClipRect: the area on the temporary surface within shadowPaintRect
* shadowPaintRect: the area to paint on the temp surface, larger than shadowRect // that we will NOT paint in
* so that blurs still happen properly near the edges
* shadowClipRect: the area on the temporary surface within shadowPaintRect
* that we will NOT paint in
*/
nscoord blurRadius = shadowItem->mRadius; nscoord blurRadius = shadowItem->mRadius;
nsMargin blurMargin = nsMargin blurMargin =
nsContextBoxBlur::GetBlurRadiusMargin(blurRadius, twipsPerPixel); nsContextBoxBlur::GetBlurRadiusMargin(blurRadius, twipsPerPixel);
@ -4935,10 +5126,8 @@ nsContextBoxBlur::GetBlurRadiusMargin(nscoord aBlurRadius,
gfxIntSize blurRadius = ComputeBlurRadius(aBlurRadius, aAppUnitsPerDevPixel); gfxIntSize blurRadius = ComputeBlurRadius(aBlurRadius, aAppUnitsPerDevPixel);
nsMargin result; nsMargin result;
result.top = blurRadius.height * aAppUnitsPerDevPixel; result.top = result.bottom = blurRadius.height * aAppUnitsPerDevPixel;
result.right = blurRadius.width * aAppUnitsPerDevPixel; result.left = result.right = blurRadius.width * aAppUnitsPerDevPixel;
result.bottom = blurRadius.height * aAppUnitsPerDevPixel;
result.left = blurRadius.width * aAppUnitsPerDevPixel;
return result; return result;
} }

View File

@ -120,7 +120,6 @@ nsCSSBorderRenderer::nsCSSBorderRenderer(int32_t aAppUnitsPerPixel,
gfxCornerSizes& aBorderRadii, gfxCornerSizes& aBorderRadii,
const nscolor* aBorderColors, const nscolor* aBorderColors,
nsBorderColors* const* aCompositeColors, nsBorderColors* const* aCompositeColors,
int aSkipSides,
nscolor aBackgroundColor) nscolor aBackgroundColor)
: mContext(aDestContext), : mContext(aDestContext),
mOuterRect(aOuterRect), mOuterRect(aOuterRect),
@ -130,7 +129,6 @@ nsCSSBorderRenderer::nsCSSBorderRenderer(int32_t aAppUnitsPerPixel,
mBorderColors(aBorderColors), mBorderColors(aBorderColors),
mCompositeColors(aCompositeColors), mCompositeColors(aCompositeColors),
mAUPP(aAppUnitsPerPixel), mAUPP(aAppUnitsPerPixel),
mSkipSides(aSkipSides),
mBackgroundColor(aBackgroundColor) mBackgroundColor(aBackgroundColor)
{ {
if (!mCompositeColors) { if (!mCompositeColors) {

View File

@ -79,7 +79,6 @@ struct nsCSSBorderRenderer {
gfxCornerSizes& aBorderRadii, gfxCornerSizes& aBorderRadii,
const nscolor* aBorderColors, const nscolor* aBorderColors,
nsBorderColors* const* aCompositeColors, nsBorderColors* const* aCompositeColors,
int aSkipSides,
nscolor aBackgroundColor); nscolor aBackgroundColor);
gfxCornerSizes mBorderCornerDimensions; gfxCornerSizes mBorderCornerDimensions;
@ -105,8 +104,7 @@ struct nsCSSBorderRenderer {
// core app units per pixel // core app units per pixel
int32_t mAUPP; int32_t mAUPP;
// misc -- which sides to skip, the background color // the background color
int mSkipSides;
nscolor mBackgroundColor; nscolor mBackgroundColor;
// calculated values // calculated values

View File

@ -2839,11 +2839,8 @@ nsDisplayBoxShadowOuter::Paint(nsDisplayListBuilder* aBuilder,
PROFILER_LABEL("nsDisplayBoxShadowOuter", "Paint"); PROFILER_LABEL("nsDisplayBoxShadowOuter", "Paint");
for (uint32_t i = 0; i < rects.Length(); ++i) { for (uint32_t i = 0; i < rects.Length(); ++i) {
aCtx->PushState();
aCtx->IntersectClip(rects[i]);
nsCSSRendering::PaintBoxShadowOuter(presContext, *aCtx, mFrame, nsCSSRendering::PaintBoxShadowOuter(presContext, *aCtx, mFrame,
borderRect, rects[i], mOpacity); borderRect, rects[i], mOpacity);
aCtx->PopState();
} }
} }

View File

@ -849,12 +849,31 @@ nsContainerFrame::DoInlineIntrinsicWidth(nsRenderingContext *aRenderingContext,
// This frame is a first-in-flow, but it might have a previous bidi // This frame is a first-in-flow, but it might have a previous bidi
// continuation, in which case that continuation should handle the startSide // continuation, in which case that continuation should handle the startSide
// border. // border.
// For box-decoration-break:clone we setup clonePBM = startPBM + endPBM and
// add that to each line. For box-decoration-break:slice clonePBM is zero.
nscoord clonePBM = 0; // PBM = PaddingBorderMargin
const bool sliceBreak =
styleBorder->mBoxDecorationBreak == NS_STYLE_BOX_DECORATION_BREAK_SLICE;
if (!GetPrevContinuation()) { if (!GetPrevContinuation()) {
aData->currentLine += nscoord startPBM =
// clamp negative calc() to 0 // clamp negative calc() to 0
std::max(GetCoord(stylePadding->mPadding.Get(startSide), 0), 0) + std::max(GetCoord(stylePadding->mPadding.Get(startSide), 0), 0) +
styleBorder->GetComputedBorderWidth(startSide) + styleBorder->GetComputedBorderWidth(startSide) +
GetCoord(styleMargin->mMargin.Get(startSide), 0); GetCoord(styleMargin->mMargin.Get(startSide), 0);
if (MOZ_LIKELY(sliceBreak)) {
aData->currentLine += startPBM;
} else {
clonePBM = startPBM;
}
}
nscoord endPBM =
// clamp negative calc() to 0
std::max(GetCoord(stylePadding->mPadding.Get(endSide), 0), 0) +
styleBorder->GetComputedBorderWidth(endSide) +
GetCoord(styleMargin->mMargin.Get(endSide), 0);
if (MOZ_UNLIKELY(!sliceBreak)) {
clonePBM += endPBM;
} }
const nsLineList_iterator* savedLine = aData->line; const nsLineList_iterator* savedLine = aData->line;
@ -863,6 +882,9 @@ nsContainerFrame::DoInlineIntrinsicWidth(nsRenderingContext *aRenderingContext,
nsContainerFrame *lastInFlow; nsContainerFrame *lastInFlow;
for (nsContainerFrame *nif = this; nif; for (nsContainerFrame *nif = this; nif;
nif = static_cast<nsContainerFrame*>(nif->GetNextInFlow())) { nif = static_cast<nsContainerFrame*>(nif->GetNextInFlow())) {
if (aData->currentLine == 0) {
aData->currentLine = clonePBM;
}
for (nsIFrame *kid = nif->mFrames.FirstChild(); kid; for (nsIFrame *kid = nif->mFrames.FirstChild(); kid;
kid = kid->GetNextSibling()) { kid = kid->GetNextSibling()) {
if (aType == nsLayoutUtils::MIN_WIDTH) if (aType == nsLayoutUtils::MIN_WIDTH)
@ -891,12 +913,8 @@ nsContainerFrame::DoInlineIntrinsicWidth(nsRenderingContext *aRenderingContext,
// We reached the last-in-flow, but it might have a next bidi // We reached the last-in-flow, but it might have a next bidi
// continuation, in which case that continuation should handle // continuation, in which case that continuation should handle
// the endSide border. // the endSide border.
if (!lastInFlow->GetNextContinuation()) { if (MOZ_LIKELY(!lastInFlow->GetNextContinuation() && sliceBreak)) {
aData->currentLine += aData->currentLine += endPBM;
// clamp negative calc() to 0
std::max(GetCoord(stylePadding->mPadding.Get(endSide), 0), 0) +
styleBorder->GetComputedBorderWidth(endSide) +
GetCoord(styleMargin->mMargin.Get(endSide), 0);
} }
} }

View File

@ -953,6 +953,11 @@ nsIFrame::GetUsedPadding() const
int int
nsIFrame::GetSkipSides(const nsHTMLReflowState* aReflowState) const nsIFrame::GetSkipSides(const nsHTMLReflowState* aReflowState) const
{ {
if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
NS_STYLE_BOX_DECORATION_BREAK_CLONE)) {
return 0;
}
// Convert the logical skip sides to physical sides using the frame's // Convert the logical skip sides to physical sides using the frame's
// writing mode // writing mode
WritingMode writingMode = GetWritingMode(); WritingMode writingMode = GetWritingMode();

View File

@ -1782,6 +1782,10 @@ nsImageFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
int int
nsImageFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const nsImageFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const
{ {
if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
NS_STYLE_BOX_DECORATION_BREAK_CLONE)) {
return 0;
}
int skip = 0; int skip = 0;
if (nullptr != GetPrevInFlow()) { if (nullptr != GetPrevInFlow()) {
skip |= LOGICAL_SIDE_B_START; skip |= LOGICAL_SIDE_B_START;

View File

@ -115,7 +115,11 @@ nsInlineFrame::IsSelfEmpty()
!nsLayoutUtils::IsPaddingZero(padding->mPadding.GetLeft()) || !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetLeft()) ||
!IsMarginZero(margin->mMargin.GetLeft()); !IsMarginZero(margin->mMargin.GetLeft());
if (haveLeft || haveRight) { if (haveLeft || haveRight) {
if (GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) { // We skip this block and return false for box-decoration-break:clone since
// in that case all the continuations will have the border/padding/margin.
if ((GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) &&
StyleBorder()->mBoxDecorationBreak ==
NS_STYLE_BOX_DECORATION_BREAK_SLICE) {
bool haveStart, haveEnd; bool haveStart, haveEnd;
if (NS_STYLE_DIRECTION_LTR == StyleVisibility()->mDirection) { if (NS_STYLE_DIRECTION_LTR == StyleVisibility()->mDirection) {
haveStart = haveLeft; haveStart = haveLeft;
@ -491,9 +495,15 @@ nsInlineFrame::ReflowFrames(nsPresContext* aPresContext,
RestyleManager* restyleManager = aPresContext->RestyleManager(); RestyleManager* restyleManager = aPresContext->RestyleManager();
WritingMode wm = aReflowState.GetWritingMode(); WritingMode wm = aReflowState.GetWritingMode();
nscoord startEdge = 0; nscoord startEdge = 0;
const bool boxDecorationBreakClone =
MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
NS_STYLE_BOX_DECORATION_BREAK_CLONE);
// Don't offset by our start borderpadding if we have a prev continuation or // Don't offset by our start borderpadding if we have a prev continuation or
// if we're in a part of an {ib} split other than the first one. // if we're in a part of an {ib} split other than the first one. For
if (!GetPrevContinuation() && !FrameIsNonFirstInIBSplit()) { // box-decoration-break:clone we always offset our start since all
// continuations have border/padding.
if ((!GetPrevContinuation() && !FrameIsNonFirstInIBSplit()) ||
boxDecorationBreakClone) {
startEdge = aReflowState.ComputedLogicalBorderPadding().IStart(wm); startEdge = aReflowState.ComputedLogicalBorderPadding().IStart(wm);
} }
nscoord availableISize = aReflowState.AvailableISize(); nscoord availableISize = aReflowState.AvailableISize();
@ -654,8 +664,10 @@ nsInlineFrame::ReflowFrames(nsPresContext* aPresContext,
// Make sure to not include our start border and padding if we have a prev // Make sure to not include our start border and padding if we have a prev
// continuation or if we're in a part of an {ib} split other than the first // continuation or if we're in a part of an {ib} split other than the first
// one. // one. For box-decoration-break:clone we always include our start border
if (!GetPrevContinuation() && !FrameIsNonFirstInIBSplit()) { // and padding since all continuations have them.
if ((!GetPrevContinuation() && !FrameIsNonFirstInIBSplit()) ||
boxDecorationBreakClone) {
aMetrics.ISize() += aReflowState.ComputedLogicalBorderPadding().IStart(wm); aMetrics.ISize() += aReflowState.ComputedLogicalBorderPadding().IStart(wm);
} }
@ -664,11 +676,13 @@ nsInlineFrame::ReflowFrames(nsPresContext* aPresContext,
* continuation and either not in an {ib} split or the last part of it. To * continuation and either not in an {ib} split or the last part of it. To
* be the last continuation we have to be complete (so that we won't get a * be the last continuation we have to be complete (so that we won't get a
* next-in-flow) and have no non-fluid continuations on our continuation * next-in-flow) and have no non-fluid continuations on our continuation
* chain. * chain. For box-decoration-break:clone we always apply the end border and
* padding since all continuations have them.
*/ */
if (NS_FRAME_IS_COMPLETE(aStatus) && if ((NS_FRAME_IS_COMPLETE(aStatus) &&
!LastInFlow()->GetNextContinuation() && !LastInFlow()->GetNextContinuation() &&
!FrameIsNonLastInIBSplit()) { !FrameIsNonLastInIBSplit()) ||
boxDecorationBreakClone) {
aMetrics.Width() += aReflowState.ComputedLogicalBorderPadding().IEnd(wm); aMetrics.Width() += aReflowState.ComputedLogicalBorderPadding().IEnd(wm);
} }
@ -872,6 +886,11 @@ nsInlineFrame::PushFrames(nsPresContext* aPresContext,
int int
nsInlineFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const nsInlineFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const
{ {
if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
NS_STYLE_BOX_DECORATION_BREAK_CLONE)) {
return 0;
}
int skip = 0; int skip = 0;
if (!IsFirst()) { if (!IsFirst()) {
nsInlineFrame* prev = (nsInlineFrame*) GetPrevContinuation(); nsInlineFrame* prev = (nsInlineFrame*) GetPrevContinuation();

View File

@ -1076,9 +1076,12 @@ nsLineLayout::ApplyStartMargin(PerFrameData* pfd,
// in an ib split. Note that the ib sibling (block-in-inline // in an ib split. Note that the ib sibling (block-in-inline
// sibling) annotations only live on the first continuation, but we // sibling) annotations only live on the first continuation, but we
// don't want to apply the start margin for later continuations // don't want to apply the start margin for later continuations
// anyway. // anyway. For box-decoration-break:clone we apply the start-margin
if (pfd->mFrame->GetPrevContinuation() || // on all continuations.
pfd->mFrame->FrameIsNonFirstInIBSplit()) { if ((pfd->mFrame->GetPrevContinuation() ||
pfd->mFrame->FrameIsNonFirstInIBSplit()) &&
aReflowState.mStyleBorder->mBoxDecorationBreak ==
NS_STYLE_BOX_DECORATION_BREAK_SLICE) {
// Zero this out so that when we compute the max-element-width of // Zero this out so that when we compute the max-element-width of
// the frame we will properly avoid adding in the starting margin. // the frame we will properly avoid adding in the starting margin.
pfd->mMargin.IStart(frameWM) = 0; pfd->mMargin.IStart(frameWM) = 0;
@ -1160,6 +1163,9 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd,
* 3) The frame is in an {ib} split and is not the last part. * 3) The frame is in an {ib} split and is not the last part.
* *
* However, none of that applies if this is a letter frame (XXXbz why?) * However, none of that applies if this is a letter frame (XXXbz why?)
*
* For box-decoration-break:clone we apply the end margin on all
* continuations (that are not letter frames).
*/ */
if (pfd->mFrame->GetPrevContinuation() || if (pfd->mFrame->GetPrevContinuation() ||
pfd->mFrame->FrameIsNonFirstInIBSplit()) { pfd->mFrame->FrameIsNonFirstInIBSplit()) {
@ -1167,8 +1173,10 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd,
} }
if ((NS_FRAME_IS_NOT_COMPLETE(aStatus) || if ((NS_FRAME_IS_NOT_COMPLETE(aStatus) ||
pfd->mFrame->LastInFlow()->GetNextContinuation() || pfd->mFrame->LastInFlow()->GetNextContinuation() ||
pfd->mFrame->FrameIsNonLastInIBSplit()) pfd->mFrame->FrameIsNonLastInIBSplit()) &&
&& !pfd->GetFlag(PFD_ISLETTERFRAME)) { !pfd->GetFlag(PFD_ISLETTERFRAME) &&
pfd->mFrame->StyleBorder()->mBoxDecorationBreak ==
NS_STYLE_BOX_DECORATION_BREAK_SLICE) {
pfd->mMargin.IEnd(frameWM) = 0; pfd->mMargin.IEnd(frameWM) = 0;
} }
LogicalMargin usedMargins = pfd->mMargin.ConvertTo(lineWM, frameWM); LogicalMargin usedMargins = pfd->mMargin.ConvertTo(lineWM, frameWM);

View File

@ -253,8 +253,12 @@ nsSplittableFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) co
return LOGICAL_SIDES_B_BOTH; return LOGICAL_SIDES_B_BOTH;
} }
int skip = 0; if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
NS_STYLE_BOX_DECORATION_BREAK_CLONE)) {
return 0;
}
int skip = 0;
if (GetPrevInFlow()) { if (GetPrevInFlow()) {
skip |= LOGICAL_SIDE_B_START; skip |= LOGICAL_SIDE_B_START;
} }

View File

@ -550,6 +550,11 @@ nsTableCellFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
int int
nsTableCellFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const nsTableCellFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const
{ {
if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
NS_STYLE_BOX_DECORATION_BREAK_CLONE)) {
return 0;
}
int skip = 0; int skip = 0;
if (nullptr != GetPrevInFlow()) { if (nullptr != GetPrevInFlow()) {
skip |= LOGICAL_SIDE_B_START; skip |= LOGICAL_SIDE_B_START;

View File

@ -343,6 +343,11 @@ nsTableColGroupFrame::RemoveFrame(ChildListID aListID,
int int
nsTableColGroupFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const nsTableColGroupFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const
{ {
if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
NS_STYLE_BOX_DECORATION_BREAK_CLONE)) {
return 0;
}
int skip = 0; int skip = 0;
if (nullptr != GetPrevInFlow()) { if (nullptr != GetPrevInFlow()) {
skip |= 1 << LOGICAL_SIDE_B_START; skip |= 1 << LOGICAL_SIDE_B_START;

View File

@ -1409,6 +1409,11 @@ nsTableFrame::PaintTableBorderBackground(nsRenderingContext& aRenderingContext,
int int
nsTableFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const nsTableFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const
{ {
if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
NS_STYLE_BOX_DECORATION_BREAK_CLONE)) {
return 0;
}
int skip = 0; int skip = 0;
// frame attribute was accounted for in nsHTMLTableElement::MapTableBorderInto // frame attribute was accounted for in nsHTMLTableElement::MapTableBorderInto
// account for pagination // account for pagination

View File

@ -605,6 +605,11 @@ nsTableRowFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
int int
nsTableRowFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const nsTableRowFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const
{ {
if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
NS_STYLE_BOX_DECORATION_BREAK_CLONE)) {
return 0;
}
int skip = 0; int skip = 0;
if (nullptr != GetPrevInFlow()) { if (nullptr != GetPrevInFlow()) {
skip |= LOGICAL_SIDE_B_START; skip |= LOGICAL_SIDE_B_START;

View File

@ -256,6 +256,11 @@ nsTableRowGroupFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
int int
nsTableRowGroupFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const nsTableRowGroupFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const
{ {
if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
NS_STYLE_BOX_DECORATION_BREAK_CLONE)) {
return 0;
}
int skip = 0; int skip = 0;
if (nullptr != GetPrevInFlow()) { if (nullptr != GetPrevInFlow()) {
skip |= LOGICAL_SIDE_B_START; skip |= LOGICAL_SIDE_B_START;