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
authorBoris Zbarsky <bzbarsky@mit.edu>
Wed, 23 Nov 2011 12:59:51 -0500
changeset 83129 85358854403fbd5c6b1731e2eda2722deea51d98
parent 83128 c9eee0711ca6c1d8b9a152af2f9372fef4cd5f31
child 83130 5c0c7af66ec01e965d68cb42c670160bdfa64462
push id519
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 00:38:35 +0000
treeherdermozilla-beta@788ea1ef610b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs704399
milestone11.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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
layout/base/nsCSSRendering.cpp
layout/base/nsStyleConsts.h
layout/reftests/border-radius/curved-border-background-nogap-ref.html
layout/reftests/border-radius/curved-border-background-nogap.html
layout/reftests/border-radius/reftest.list
layout/reftests/box-shadow/boxshadow-mixed-ref.html
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -1572,17 +1572,25 @@ GetBackgroundClip(gfxContext *aCtx, PRUi
                   /* out */ BackgroundClipState* aClipState)
 {
   aClipState->mBGClipArea = aBorderArea;
   aClipState->mCustomClip = false;
   aClipState->mRadiiAreOuter = true;
   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();
     }
     aForFrame->ApplySkipSides(border);
     aClipState->mBGClipArea.Deflate(border);
 
     if (aHaveRoundedCorners) {
@@ -2376,18 +2384,23 @@ nsCSSRendering::PaintBackgroundWithSC(ns
     // don't need to draw outside the padding area.  In either case,
     // if the borders are rounded, make sure we use the same inner
     // radii as the border code will.
     // The background-color is drawn based on the bottom
     // background-clip.
     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,
                       &clipState);
   }
 
   // If we might be using a background color, go ahead and set it now.
   if (drawBackgroundColor && !isCanvasFrame)
@@ -2423,18 +2436,20 @@ nsCSSRendering::PaintBackgroundWithSC(ns
   }
 
   if (drawBackgroundImage) {
     bool clipSet = false;
     NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) {
       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
           // already called GetBackgroundClip above and it stored its results
           // in clipState.
           if (clipSet) {
             GetBackgroundClip(ctx, currentBackgroundClip, aForFrame,
                               aBorderArea, aDirtyRect, haveRoundedCorners,
--- a/layout/base/nsStyleConsts.h
+++ b/layout/base/nsStyleConsts.h
@@ -268,16 +268,22 @@ static inline mozilla::css::Side operato
 #define NS_STYLE_BG_ATTACHMENT_SCROLL     0
 #define NS_STYLE_BG_ATTACHMENT_FIXED      1
 
 // See nsStyleBackground
 // Code depends on these constants having the same values as BG_ORIGIN_*
 #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
 #define NS_STYLE_BG_INLINE_POLICY_CONTINUOUS    1
 #define NS_STYLE_BG_INLINE_POLICY_BOUNDING_BOX  2
 
 // See nsStyleBackground
 // Code depends on these constants having the same values as BG_CLIP_*
new file mode 100644
--- /dev/null
+++ b/layout/reftests/border-radius/curved-border-background-nogap-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<style>
+  div {
+    width: 100px;
+    height: 100px;
+    background: black;
+  }
+</style>
+<div></div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/border-radius/curved-border-background-nogap.html
@@ -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>
--- a/layout/reftests/border-radius/reftest.list
+++ b/layout/reftests/border-radius/reftest.list
@@ -74,8 +74,11 @@ fails-if(Android) == scrollbar-clamping-
 == corner-joins-1.xhtml corner-joins-1-ref.xhtml
 random-if(winWidget) HTTP(..) == corner-joins-2.xhtml corner-joins-2-ref.xhtml
 
 == scroll-1.html scroll-1-ref.html # see bug 602892
 
 == 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
--- a/layout/reftests/box-shadow/boxshadow-mixed-ref.html
+++ b/layout/reftests/box-shadow/boxshadow-mixed-ref.html
@@ -1,1 +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>