Bug 704399. When doing the 'restrict background painting to the padding area' optimization, actually restrict it to padding area plus 1px on each side to deal with seams caused by curved borders better. r=roc

This commit is contained in:
Boris Zbarsky 2011-11-23 12:59:51 -05:00
parent c2dbf0e344
commit 3687e2d7b5
6 changed files with 75 additions and 6 deletions

View File

@ -1577,7 +1577,15 @@ GetBackgroundClip(gfxContext *aCtx, PRUint8 aBackgroundClip,
aClipState->mClippedRadii = aBGRadii;
if (aBackgroundClip != NS_STYLE_BG_CLIP_BORDER) {
nsMargin border = aForFrame->GetUsedBorder();
if (aBackgroundClip != NS_STYLE_BG_CLIP_PADDING) {
if (aBackgroundClip == NS_STYLE_BG_CLIP_MOZ_ALMOST_PADDING) {
// Reduce |border| by 1px (device pixels) on all sides, if
// possible, so that we don't get antialiasing seams between the
// background and border.
border.top = NS_MAX(0, border.top - aAppUnitsPerPixel);
border.right = NS_MAX(0, border.right - aAppUnitsPerPixel);
border.bottom = NS_MAX(0, border.bottom - aAppUnitsPerPixel);
border.left = NS_MAX(0, border.left - aAppUnitsPerPixel);
} else if (aBackgroundClip != NS_STYLE_BG_CLIP_PADDING) {
NS_ASSERTION(aBackgroundClip == NS_STYLE_BG_CLIP_CONTENT,
"unexpected background-clip");
border += aForFrame->GetUsedPadding();
@ -2381,8 +2389,13 @@ nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext,
currentBackgroundClip = bg->BottomLayer().mClip;
isSolidBorder =
(aFlags & PAINTBG_WILL_PAINT_BORDER) && IsOpaqueBorder(aBorder);
if (isSolidBorder && currentBackgroundClip == NS_STYLE_BG_CLIP_BORDER)
currentBackgroundClip = NS_STYLE_BG_CLIP_PADDING;
if (isSolidBorder && currentBackgroundClip == NS_STYLE_BG_CLIP_BORDER) {
// If we have rounded corners, we need to inflate the background
// drawing area a bit to avoid seams between the border and
// background.
currentBackgroundClip = haveRoundedCorners ?
NS_STYLE_BG_CLIP_MOZ_ALMOST_PADDING : NS_STYLE_BG_CLIP_PADDING;
}
GetBackgroundClip(ctx, currentBackgroundClip, aForFrame, aBorderArea,
aDirtyRect, haveRoundedCorners, bgRadii, appUnitsPerPixel,
@ -2428,8 +2441,10 @@ nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext,
const nsStyleBackground::Layer &layer = bg->mLayers[i];
if (!aBGClipRect) {
PRUint8 newBackgroundClip = layer.mClip;
if (isSolidBorder && newBackgroundClip == NS_STYLE_BG_CLIP_BORDER)
newBackgroundClip = NS_STYLE_BG_CLIP_PADDING;
if (isSolidBorder && newBackgroundClip == NS_STYLE_BG_CLIP_BORDER) {
newBackgroundClip = haveRoundedCorners ?
NS_STYLE_BG_CLIP_MOZ_ALMOST_PADDING : NS_STYLE_BG_CLIP_PADDING;
}
if (currentBackgroundClip != newBackgroundClip || !clipSet) {
currentBackgroundClip = newBackgroundClip;
// If clipSet is false that means this is the bottom layer and we

View File

@ -273,6 +273,12 @@ static inline mozilla::css::Side operator++(mozilla::css::Side& side, int) {
#define NS_STYLE_BG_CLIP_BORDER 0
#define NS_STYLE_BG_CLIP_PADDING 1
#define NS_STYLE_BG_CLIP_CONTENT 2
// A magic value that we use for our "pretend that background-clip is
// 'padding' when we have a solid border" optimization. This isn't
// actually equal to NS_STYLE_BG_CLIP_PADDING because using that
// causes antialiasing seams between the background and border. This
// is a backend-only value.
#define NS_STYLE_BG_CLIP_MOZ_ALMOST_PADDING 127
// See nsStyleBackground
#define NS_STYLE_BG_INLINE_POLICY_EACH_BOX 0

View File

@ -0,0 +1,9 @@
<!DOCTYPE html>
<style>
div {
width: 100px;
height: 100px;
background: black;
}
</style>
<div></div>

View File

@ -0,0 +1,36 @@
<!DOCTYPE html>
<style>
/*
Turns out that the antialiasing on the outer edge of a block with
border-radius is not consistent if the width and border-width are changed
even if the resulting shape should look the same. So clip out the part
that's too far from the center
*/
div.outer {
width: 100px;
height: 100px;
overflow: hidden;
}
/* We want the following constraints to be satisfied:
1) Entire inner div content area is contained inside the 100px square.
2) Entire 100px square is contained inside the outer circle of the inner
div's border.
This requires that the inner div width/height be < 100px and that the
radius of the outer circle be at least 50 * sqrt(2). Let's go with a 75px
radius for that outer circle. We then need to shift our inner div up and
to the left by 25px to center it in the clipping region.
*/
div.inner {
width: 50px;
height: 50px;
border: 50px solid black;
background: black;
border-radius: 100px;
position: relative;
top: -25px;
left: -25px;
}
</style>
<div class="outer"><div class="inner"></div></div>

View File

@ -79,3 +79,6 @@ random-if(winWidget) HTTP(..) == corner-joins-2.xhtml corner-joins-2-ref.xhtml
== zero-radius-clip-1.html zero-radius-clip-ref.html
== iframe-1.html iframe-1-ref.html
# Test for antialiasing gaps between background and border
fails-if(winWidget) == curved-border-background-nogap.html curved-border-background-nogap-ref.html

View File

@ -1 +1 @@
<div style="background-color: blue; border: 2px solid red; border-radius: 10px; width: 300px; height: 300px; position: absolute; top: 10px; left: 10px;">inset and outset</div><div style="border-radius: 10px; background-color: green; width: 304px; height: 304px; position: absolute; top: 10px; left: 360px;">&nbsp;</div>
<div style="background: blue padding-box; border: 2px solid red; border-radius: 10px; width: 300px; height: 300px; position: absolute; top: 10px; left: 10px;">inset and outset</div><div style="border-radius: 10px; background-color: green; width: 304px; height: 304px; position: absolute; top: 10px; left: 360px;">&nbsp;</div>