Bug 798964 - Add nsDisplayBackground color and make the bounds of nsDisplayBackground match the image. r=roc
authorMatt Woodrow <mwoodrow@mozilla.com>
Thu, 25 Oct 2012 18:32:25 +1300
changeset 111461 e8a8bf41e0c4e7fbad6261d2c92ec5417cfe2561
parent 111460 6acf30e09a34b644204b166761d200c589d76631
child 111462 c95958e3b85db61c0842aa8e1dc23d35709599ad
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersroc
bugs798964
milestone19.0a1
Bug 798964 - Add nsDisplayBackground color and make the bounds of nsDisplayBackground match the image. r=roc
layout/base/nsCSSRendering.cpp
layout/base/nsCSSRendering.h
layout/base/nsDisplayItemTypesList.h
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/reftests/backgrounds/reftest.list
layout/reftests/css-gradients/reftest.list
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -1500,17 +1500,17 @@ nsCSSRendering::PaintBackground(nsPresCo
   SAMPLE_LABEL("nsCSSRendering", "PaintBackground");
   NS_PRECONDITION(aForFrame,
                   "Frame is expected to be provided to PaintBackground");
 
   nsStyleContext *sc;
   if (!FindBackground(aPresContext, aForFrame, &sc)) {
     // We don't want to bail out if moz-appearance is set on a root
     // node. If it has a parent content node, bail because it's not
-    // a root, other wise keep going in order to let the theme stuff
+    // a root, otherwise keep going in order to let the theme stuff
     // draw the background. The canvas really should be drawing the
     // bg, but there's no way to hook that up via css.
     if (!aForFrame->GetStyleDisplay()->mAppearance) {
       return;
     }
 
     nsIContent* content = aForFrame->GetContent();
     if (!content || content->GetParent()) {
@@ -1521,16 +1521,52 @@ nsCSSRendering::PaintBackground(nsPresCo
   }
 
   PaintBackgroundWithSC(aPresContext, aRenderingContext, aForFrame,
                         aDirtyRect, aBorderArea, sc,
                         *aForFrame->GetStyleBorder(), aFlags,
                         aBGClipRect, aLayer);
 }
 
+void
+nsCSSRendering::PaintBackgroundColor(nsPresContext* aPresContext,
+                                     nsRenderingContext& aRenderingContext,
+                                     nsIFrame* aForFrame,
+                                     const nsRect& aDirtyRect,
+                                     const nsRect& aBorderArea,
+                                     uint32_t aFlags)
+{
+  SAMPLE_LABEL("nsCSSRendering", "PaintBackgroundColor");
+  NS_PRECONDITION(aForFrame,
+                  "Frame is expected to be provided to PaintBackground");
+
+  nsStyleContext *sc;
+  if (!FindBackground(aPresContext, aForFrame, &sc)) {
+    // We don't want to bail out if moz-appearance is set on a root
+    // node. If it has a parent content node, bail because it's not
+    // a root, other wise keep going in order to let the theme stuff
+    // draw the background. The canvas really should be drawing the
+    // bg, but there's no way to hook that up via css.
+    if (!aForFrame->GetStyleDisplay()->mAppearance) {
+      return;
+    }
+
+    nsIContent* content = aForFrame->GetContent();
+    if (!content || content->GetParent()) {
+      return;
+    }
+
+    sc = aForFrame->GetStyleContext();
+  }
+
+  PaintBackgroundColorWithSC(aPresContext, aRenderingContext, aForFrame,
+                             aDirtyRect, aBorderArea, sc,
+                             *aForFrame->GetStyleBorder(), aFlags);
+}
+
 static bool
 IsOpaqueBorderEdge(const nsStyleBorder& aBorder, mozilla::css::Side aSide)
 {
   if (aBorder.GetComputedBorder().Side(aSide) == 0)
     return true;
   switch (aBorder.GetBorderStyle(aSide)) {
   case NS_STYLE_BORDER_STYLE_SOLID:
   case NS_STYLE_BORDER_STYLE_GROOVE:
@@ -2399,21 +2435,20 @@ nsCSSRendering::PaintBackgroundWithSC(ns
   bool drawBackgroundColor;
 
   nscolor bgColor = DetermineBackgroundColor(aPresContext,
                                              aBackgroundSC,
                                              aForFrame,
                                              drawBackgroundImage,
                                              drawBackgroundColor);
 
-  // If we're not drawing the back-most layer, we don't want to draw the
+  // If we're drawing a specific layer, we don't want to draw the
   // background color.
   const nsStyleBackground *bg = aBackgroundSC->GetStyleBackground();
-  if (drawBackgroundColor && aLayer >= 0 &&
-      static_cast<uint32_t>(aLayer) != bg->mImageCount - 1) {
+  if (drawBackgroundColor && aLayer >= 0) {
     drawBackgroundColor = false;
   }
 
   // At this point, drawBackgroundImage and drawBackgroundColor are
   // true if and only if we are actually supposed to paint an image or
   // color into aDirtyRect, respectively.
   if (!drawBackgroundImage && !drawBackgroundColor)
     return;
@@ -2564,16 +2599,109 @@ nsCSSRendering::PaintBackgroundWithSC(ns
                                     state.mAnchor + aBorderArea.TopLeft(),
                                     clipState.mDirtyRect);
         }
       }
     }
   }
 }
 
+void
+nsCSSRendering::PaintBackgroundColorWithSC(nsPresContext* aPresContext,
+                                           nsRenderingContext& aRenderingContext,
+                                           nsIFrame* aForFrame,
+                                           const nsRect& aDirtyRect,
+                                           const nsRect& aBorderArea,
+                                           nsStyleContext* aBackgroundSC,
+                                           const nsStyleBorder& aBorder,
+                                           uint32_t aFlags)
+{
+  NS_PRECONDITION(aForFrame,
+                  "Frame is expected to be provided to PaintBackground");
+
+  // Check to see if we have an appearance defined.  If so, we let the theme
+  // renderer draw the background and bail out.
+  const nsStyleDisplay* displayData = aForFrame->GetStyleDisplay();
+  if (displayData->mAppearance) {
+    nsITheme *theme = aPresContext->GetTheme();
+    if (theme && theme->ThemeSupportsWidget(aPresContext, aForFrame,
+                                            displayData->mAppearance)) {
+      NS_ERROR("Shouldn't be trying to paint a background color if we are themed!");
+      return;
+    }
+  }
+
+  NS_ASSERTION(!IsCanvasFrame(aForFrame), "Should not be trying to paint a background color for canvas frames!");
+
+  // Determine whether we are drawing background images and/or
+  // background colors.
+  bool drawBackgroundImage;
+  bool drawBackgroundColor;
+
+  nscolor bgColor = DetermineBackgroundColor(aPresContext,
+                                             aBackgroundSC,
+                                             aForFrame,
+                                             drawBackgroundImage,
+                                             drawBackgroundColor);
+
+  NS_ASSERTION(drawBackgroundColor, "Should not be trying to paint a background color if we don't have one");
+
+  // Compute the outermost boundary of the area that might be painted.
+  gfxContext *ctx = aRenderingContext.ThebesContext();
+  nscoord appUnitsPerPixel = aPresContext->AppUnitsPerDevPixel();
+
+  // Same coordinate space as aBorderArea
+  gfxCornerSizes bgRadii;
+  bool haveRoundedCorners;
+  {
+    nscoord radii[8];
+    nsSize frameSize = aForFrame->GetSize();
+    if (&aBorder == aForFrame->GetStyleBorder() &&
+        frameSize == aBorderArea.Size()) {
+      haveRoundedCorners = aForFrame->GetBorderRadii(radii);
+    } else {
+      haveRoundedCorners = nsIFrame::ComputeBorderRadii(aBorder.mBorderRadius,
+                                   frameSize, aBorderArea.Size(),
+                                   aForFrame->GetSkipSides(), radii);
+    }
+    if (haveRoundedCorners)
+      ComputePixelRadii(radii, appUnitsPerPixel, &bgRadii);
+  }
+
+  // The background is rendered over the 'background-clip' area,
+  // which is normally equal to the border area but may be reduced
+  // to the padding area by CSS.  Also, if the border is solid, we
+  // 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.
+  const nsStyleBackground *bg = aBackgroundSC->GetStyleBackground();
+  uint8_t currentBackgroundClip = bg->BottomLayer().mClip;
+  bool isSolidBorder =
+    (aFlags & PAINTBG_WILL_PAINT_BORDER) && IsOpaqueBorder(aBorder);
+  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;
+  }
+
+  BackgroundClipState clipState;
+  GetBackgroundClip(ctx, currentBackgroundClip, aForFrame, aBorderArea,
+                    aDirtyRect, haveRoundedCorners, bgRadii, appUnitsPerPixel,
+                    &clipState);
+
+  ctx->SetColor(gfxRGBA(bgColor));
+
+  gfxContextAutoSaveRestore autoSR;
+  DrawBackgroundColor(clipState, ctx, haveRoundedCorners, appUnitsPerPixel);
+}
+
 static inline bool
 IsTransformed(nsIFrame* aForFrame, nsIFrame* aTopFrame)
 {
   for (nsIFrame* f = aForFrame; f != aTopFrame; f = f->GetParent()) {
     if (f->IsTransformed()) {
       return true;
     }
   }
--- a/layout/base/nsCSSRendering.h
+++ b/layout/base/nsCSSRendering.h
@@ -332,16 +332,23 @@ struct nsCSSRendering {
   static void PaintBackground(nsPresContext* aPresContext,
                               nsRenderingContext& aRenderingContext,
                               nsIFrame* aForFrame,
                               const nsRect& aDirtyRect,
                               const nsRect& aBorderArea,
                               uint32_t aFlags,
                               nsRect* aBGClipRect = nullptr,
                               int32_t aLayer = -1);
+ 
+  static void PaintBackgroundColor(nsPresContext* aPresContext,
+                                   nsRenderingContext& aRenderingContext,
+                                   nsIFrame* aForFrame,
+                                   const nsRect& aDirtyRect,
+                                   const nsRect& aBorderArea,
+                                   uint32_t aFlags);
 
   /**
    * Same as |PaintBackground|, except using the provided style structs.
    * This short-circuits the code that ensures that the root element's
    * background is drawn on the canvas.
    * The aLayer parameter allows you to paint a single layer of the background.
    * The default value for aLayer, -1, means that all layers will be painted.
    * The background color will only be painted if the back-most layer is also
@@ -353,16 +360,24 @@ struct nsCSSRendering {
                                     const nsRect& aDirtyRect,
                                     const nsRect& aBorderArea,
                                     nsStyleContext *aStyleContext,
                                     const nsStyleBorder& aBorder,
                                     uint32_t aFlags,
                                     nsRect* aBGClipRect = nullptr,
                                     int32_t aLayer = -1);
 
+  static void PaintBackgroundColorWithSC(nsPresContext* aPresContext,
+                                         nsRenderingContext& aRenderingContext,
+                                         nsIFrame* aForFrame,
+                                         const nsRect& aDirtyRect,
+                                         const nsRect& aBorderArea,
+                                         nsStyleContext *aStyleContext,
+                                         const nsStyleBorder& aBorder,
+                                         uint32_t aFlags);
   /**
    * Returns the rectangle covered by the given background layer image, taking
    * into account background positioning, sizing, and repetition, but not
    * clipping.
    */
   static nsRect GetBackgroundLayerRect(nsPresContext* aPresContext,
                                        nsIFrame* aForFrame,
                                        const nsRect& aBorderArea,
--- a/layout/base/nsDisplayItemTypesList.h
+++ b/layout/base/nsDisplayItemTypesList.h
@@ -1,10 +1,11 @@
 DECLARE_DISPLAY_ITEM_TYPE(ALT_FEEDBACK)
 DECLARE_DISPLAY_ITEM_TYPE(BACKGROUND)
+DECLARE_DISPLAY_ITEM_TYPE(BACKGROUND_COLOR)
 DECLARE_DISPLAY_ITEM_TYPE(BORDER)
 DECLARE_DISPLAY_ITEM_TYPE(BOX_SHADOW_OUTER)
 DECLARE_DISPLAY_ITEM_TYPE(BOX_SHADOW_INNER)
 DECLARE_DISPLAY_ITEM_TYPE(BULLET)
 DECLARE_DISPLAY_ITEM_TYPE(BUTTON_BORDER_BACKGROUND)
 DECLARE_DISPLAY_ITEM_TYPE(BUTTON_BOX_SHADOW_OUTER)
 DECLARE_DISPLAY_ITEM_TYPE(BUTTON_FOREGROUND)
 DECLARE_DISPLAY_ITEM_TYPE(CANVAS)
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -1526,24 +1526,39 @@ nsDisplayBackground::~nsDisplayBackgroun
 }
 
 /*static*/ nsresult
 nsDisplayBackground::AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuilder,
                                                 nsIFrame* aFrame,
                                                 nsDisplayList* aList,
                                                 nsDisplayBackground** aBackground)
 {
-  nsStyleContext* bgSC;
+  nsStyleContext* bgSC = nullptr;
   const nsStyleBackground* bg = nullptr;
   nsPresContext* presContext = aFrame->PresContext();
   if (!aFrame->IsThemed() &&
       nsCSSRendering::FindBackground(presContext, aFrame, &bgSC)) {
     bg = bgSC->GetStyleBackground();
   }
 
+  bool drawBackgroundColor = false;
+  nscolor color;
+  if (!nsCSSRendering::IsCanvasFrame(aFrame) && bg) {
+    bool drawBackgroundImage;
+    color =
+      nsCSSRendering::DetermineBackgroundColor(presContext, bgSC, aFrame,
+                                               drawBackgroundImage, drawBackgroundColor);
+  }
+
+  // Even if we don't actually have a background color to paint, we still need
+  // to create the item because it's used for hit testing.
+  aList->AppendNewToTop(
+      new (aBuilder) nsDisplayBackgroundColor(aBuilder, aFrame,
+                                              drawBackgroundColor ? color : NS_RGBA(0, 0, 0, 0)));
+ 
   // Passing bg == nullptr in this macro will result in one iteration with
   // i = 0.
   bool backgroundSet = !aBackground;
   NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) {
     nsDisplayBackground* bgItem =
       new (aBuilder) nsDisplayBackground(aBuilder, aFrame, i);
     nsresult rv = aList->AppendNewToTop(bgItem);
     if (rv != NS_OK) {
@@ -1874,40 +1889,43 @@ nsDisplayBackground::ComputeVisibility(n
   // Return false if the background was propagated away from this
   // frame. We don't want this display item to show up and confuse
   // anything.
   nsStyleContext* bgSC;
   return mIsThemed ||
     nsCSSRendering::FindBackground(mFrame->PresContext(), mFrame, &bgSC);
 }
 
-nsRegion
-nsDisplayBackground::GetInsideClipRegion(nsPresContext* aPresContext,
+/* static */ nsRegion
+nsDisplayBackground::GetInsideClipRegion(nsDisplayItem* aItem,
+                                         nsPresContext* aPresContext,
                                          uint8_t aClip, const nsRect& aRect,
                                          bool* aSnap)
 {
   nsRegion result;
   if (aRect.IsEmpty())
     return result;
 
+  nsIFrame *frame = aItem->GetUnderlyingFrame();
+
   nscoord radii[8];
   nsRect clipRect;
   bool haveRadii;
   switch (aClip) {
   case NS_STYLE_BG_CLIP_BORDER:
-    haveRadii = mFrame->GetBorderRadii(radii);
-    clipRect = nsRect(ToReferenceFrame(), mFrame->GetSize());
+    haveRadii = frame->GetBorderRadii(radii);
+    clipRect = nsRect(aItem->ToReferenceFrame(), frame->GetSize());
     break;
   case NS_STYLE_BG_CLIP_PADDING:
-    haveRadii = mFrame->GetPaddingBoxBorderRadii(radii);
-    clipRect = mFrame->GetPaddingRect() - mFrame->GetPosition() + ToReferenceFrame();
+    haveRadii = frame->GetPaddingBoxBorderRadii(radii);
+    clipRect = frame->GetPaddingRect() - frame->GetPosition() + aItem->ToReferenceFrame();
     break;
   case NS_STYLE_BG_CLIP_CONTENT:
-    haveRadii = mFrame->GetContentBoxBorderRadii(radii);
-    clipRect = mFrame->GetContentRect() - mFrame->GetPosition() + ToReferenceFrame();
+    haveRadii = frame->GetContentBoxBorderRadii(radii);
+    clipRect = frame->GetContentRect() - frame->GetPosition() + aItem->ToReferenceFrame();
     break;
   default:
     NS_NOTREACHED("Unknown clip type");
     return result;
   }
 
   if (haveRadii) {
     *aSnap = false;
@@ -1931,38 +1949,32 @@ nsDisplayBackground::GetOpaqueRegion(nsD
     return result;
   }
 
   nsStyleContext* bgSC;
   nsPresContext* presContext = mFrame->PresContext();
   if (!nsCSSRendering::FindBackground(presContext, mFrame, &bgSC))
     return result;
   const nsStyleBackground* bg = bgSC->GetStyleBackground();
-  const nsStyleBackground::Layer& bottomLayer = bg->BottomLayer();
 
   *aSnap = true;
 
-  nsRect borderBox = nsRect(ToReferenceFrame(), mFrame->GetSize());
-  if (mIsBottommostLayer && NS_GET_A(bg->mBackgroundColor) == 255 &&
-      !nsCSSRendering::IsCanvasFrame(mFrame)) {
-    result = GetInsideClipRegion(presContext, bottomLayer.mClip, borderBox, aSnap);
-  }
-
   // For policies other than EACH_BOX, don't try to optimize here, since
   // this could easily lead to O(N^2) behavior inside InlineBackgroundData,
   // which expects frames to be sent to it in content order, not reverse
   // content order which we'll produce here.
   // Of course, if there's only one frame in the flow, it doesn't matter.
   if (bg->mBackgroundInlinePolicy == NS_STYLE_BG_INLINE_POLICY_EACH_BOX ||
       (!mFrame->GetPrevContinuation() && !mFrame->GetNextContinuation())) {
     const nsStyleBackground::Layer& layer = bg->mLayers[mLayer];
     if (layer.mImage.IsOpaque()) {
+      nsRect borderBox = nsRect(ToReferenceFrame(), mFrame->GetSize());
       nsRect r = nsCSSRendering::GetBackgroundLayerRect(presContext, mFrame,
           borderBox, *bg, layer);
-      result.Or(result, GetInsideClipRegion(presContext, layer.mClip, r, aSnap));
+      result.Or(result, GetInsideClipRegion(this, presContext, layer.mClip, r, aSnap));
     }
   }
 
   return result;
 }
 
 bool
 nsDisplayBackground::IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) {
@@ -2041,42 +2053,49 @@ nsDisplayBackground::RenderingMightDepen
   nsPresContext* presContext = mFrame->PresContext();
   nsStyleContext *bgSC;
   bool hasBG =
     nsCSSRendering::FindBackground(presContext, mFrame, &bgSC);
   if (!hasBG)
     return false;
   const nsStyleBackground* bg = bgSC->GetStyleBackground();
 
-  NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) {
-    const nsStyleBackground::Layer &layer = bg->mLayers[i];
-    if (layer.RenderingMightDependOnFrameSize()) {
-      return true;
-    }
+  const nsStyleBackground::Layer &layer = bg->mLayers[mLayer];
+  if (layer.RenderingMightDependOnFrameSize()) {
+    return true;
   }
   return false;
 }
 
 bool
 nsDisplayBackground::ShouldFixToViewport(nsDisplayListBuilder* aBuilder)
 {
   return mIsFixed;
 }
 
+static void CheckForBorderItem(nsDisplayItem *aItem, uint32_t& aFlags)
+{
+  nsDisplayItem* nextItem = aItem->GetAbove();
+  while (nextItem && nextItem->GetType() == nsDisplayItem::TYPE_BACKGROUND) {
+    nextItem = nextItem->GetAbove();
+  }
+  if (nextItem && 
+      nextItem->GetUnderlyingFrame() == aItem->GetUnderlyingFrame() &&
+      nextItem->GetType() == nsDisplayItem::TYPE_BORDER) {
+    aFlags |= nsCSSRendering::PAINTBG_WILL_PAINT_BORDER;
+  }
+}
+
 void
 nsDisplayBackground::Paint(nsDisplayListBuilder* aBuilder,
                            nsRenderingContext* aCtx) {
 
   nsPoint offset = ToReferenceFrame();
   uint32_t flags = aBuilder->GetBackgroundPaintFlags();
-  nsDisplayItem* nextItem = GetAbove();
-  if (nextItem && nextItem->GetUnderlyingFrame() == mFrame &&
-      nextItem->GetType() == TYPE_BORDER) {
-    flags |= nsCSSRendering::PAINTBG_WILL_PAINT_BORDER;
-  }
+  CheckForBorderItem(this, flags);
   nsCSSRendering::PaintBackground(mFrame->PresContext(), *aCtx, mFrame,
                                   mVisibleRect,
                                   nsRect(offset, mFrame->GetSize()),
                                   flags, nullptr, mLayer);
 }
 
 void nsDisplayBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                                     const nsDisplayItemGeometry* aGeometry,
@@ -2097,40 +2116,117 @@ void nsDisplayBackground::ComputeInvalid
     } else {
       aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds);
     }
   }
 }
 
 nsRect
 nsDisplayBackground::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
-  nsRect r(nsPoint(0,0), mFrame->GetSize());
+  *aSnap = true;
   nsPresContext* presContext = mFrame->PresContext();
 
   if (mIsThemed) {
+    nsRect r(nsPoint(0,0), mFrame->GetSize());
     presContext->GetTheme()->
         GetWidgetOverflow(presContext->DeviceContext(), mFrame,
                           mFrame->GetStyleDisplay()->mAppearance, &r);
 #ifdef XP_MACOSX
     // Bug 748219
     r.Inflate(mFrame->PresContext()->AppUnitsPerDevPixel());
 #endif
+
+    return r + ToReferenceFrame();
   }
 
-  *aSnap = true;
-  return r + ToReferenceFrame();
+  nsStyleContext* bgSC;
+  if (!nsCSSRendering::FindBackground(presContext, mFrame, &bgSC)) {
+    return nsRect();
+  }
+
+  const nsStyleBackground* bg = bgSC->GetStyleBackground();
+  nsRect borderBox = nsRect(ToReferenceFrame(), mFrame->GetSize());
+  const nsStyleBackground::Layer& layer = bg->mLayers[mLayer];
+  return nsCSSRendering::GetBackgroundLayerRect(presContext, mFrame,
+                                                borderBox, *bg, layer);
 }
 
 uint32_t
 nsDisplayBackground::GetPerFrameKey()
 {
   return (mLayer << nsDisplayItem::TYPE_BITS) |
     nsDisplayItem::GetPerFrameKey();
 }
 
+void
+nsDisplayBackgroundColor::Paint(nsDisplayListBuilder* aBuilder,
+                                nsRenderingContext* aCtx) 
+{
+  if (mColor == NS_RGBA(0, 0, 0, 0)) {
+    return;
+  }
+
+  nsPoint offset = ToReferenceFrame();
+  uint32_t flags = aBuilder->GetBackgroundPaintFlags();
+  CheckForBorderItem(this, flags);
+  nsCSSRendering::PaintBackgroundColor(mFrame->PresContext(), *aCtx, mFrame,
+                                       mVisibleRect,
+                                       nsRect(offset, mFrame->GetSize()),
+                                       flags);
+}
+
+nsRegion
+nsDisplayBackgroundColor::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
+                                          bool* aSnap) 
+{
+  if (NS_GET_A(mColor) != 255) {
+    return nsRegion();
+  }
+
+  nsStyleContext* bgSC;
+  nsPresContext* presContext = mFrame->PresContext();
+  if (!nsCSSRendering::FindBackground(presContext, mFrame, &bgSC))
+    return nsRegion();
+  const nsStyleBackground* bg = bgSC->GetStyleBackground();
+  const nsStyleBackground::Layer& bottomLayer = bg->BottomLayer();
+
+  *aSnap = true;
+
+  nsRect borderBox = nsRect(ToReferenceFrame(), mFrame->GetSize());
+  return nsDisplayBackground::GetInsideClipRegion(this, presContext, bottomLayer.mClip, borderBox, aSnap);
+}
+
+bool
+nsDisplayBackgroundColor::IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) 
+{
+  *aColor = mColor;
+  nsStyleContext* bgSC;
+  nsPresContext* presContext = mFrame->PresContext();
+  if (!nsCSSRendering::FindBackground(presContext, mFrame, &bgSC))
+    return true;
+
+  const nsStyleBackground* bg = bgSC->GetStyleBackground();
+  return (!nsLayoutUtils::HasNonZeroCorner(mFrame->GetStyleBorder()->mBorderRadius) &&
+          bg->BottomLayer().mClip == NS_STYLE_BG_CLIP_BORDER);
+}
+
+void
+nsDisplayBackgroundColor::HitTest(nsDisplayListBuilder* aBuilder,
+                                  const nsRect& aRect,
+                                  HitTestState* aState,
+                                  nsTArray<nsIFrame*> *aOutFrames)
+{
+  if (!RoundedBorderIntersectsRect(mFrame, ToReferenceFrame(), aRect)) {
+    // aRect doesn't intersect our border-radius curve.
+    return;
+  }
+
+  aOutFrames->AppendElement(mFrame);
+}
+
 nsRect
 nsDisplayOutline::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
   *aSnap = false;
   return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
 }
 
 void
 nsDisplayOutline::Paint(nsDisplayListBuilder* aBuilder,
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -1829,22 +1829,22 @@ public:
   {
     return new nsDisplayBackgroundGeometry(this, aBuilder);
   }
 
   virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                          const nsDisplayItemGeometry* aGeometry,
                                          nsRegion* aInvalidRegion);
 
+  static nsRegion GetInsideClipRegion(nsDisplayItem* aItem, nsPresContext* aPresContext, uint8_t aClip,
+                                      const nsRect& aRect, bool* aSnap);
 protected:
   typedef class mozilla::layers::ImageContainer ImageContainer;
   typedef class mozilla::layers::ImageLayer ImageLayer;
 
-  nsRegion GetInsideClipRegion(nsPresContext* aPresContext, uint8_t aClip,
-                               const nsRect& aRect, bool* aSnap);
 
   bool TryOptimizeToImageLayer(nsDisplayListBuilder* aBuilder);
   bool IsSingleFixedPositionImage(nsDisplayListBuilder* aBuilder, const nsRect& aClipRect);
   void ConfigureLayer(ImageLayer* aLayer);
 
   /* Used to cache mFrame->IsThemed() since it isn't a cheap call */
   bool mIsThemed;
   /* true if this item represents a background-attachment:fixed layer and
@@ -1855,16 +1855,37 @@ protected:
   nsITheme::Transparency mThemeTransparency;
 
   /* If this background can be a simple image layer, we store the format here. */
   nsRefPtr<ImageContainer> mImageContainer;
   gfxRect mDestRect;
   uint32_t mLayer;
 };
 
+class nsDisplayBackgroundColor : public nsDisplayItem
+{
+public:
+  nsDisplayBackgroundColor(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nscolor aColor)
+    : nsDisplayItem(aBuilder, aFrame)
+    , mColor(aColor)
+  { }
+
+  virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE;
+  
+  virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
+                                   bool* aSnap) MOZ_OVERRIDE;
+  virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) MOZ_OVERRIDE;
+  virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
+                       HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) MOZ_OVERRIDE;
+
+  NS_DISPLAY_DECL_NAME("BackgroundColor", TYPE_BACKGROUND_COLOR)
+
+  nscolor mColor;
+};
+
 /**
  * The standard display item to paint the outer CSS box-shadows of a frame.
  */
 class nsDisplayBoxShadowOuter : public nsDisplayItem {
 public:
   nsDisplayBoxShadowOuter(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
     : nsDisplayItem(aBuilder, aFrame) {
     MOZ_COUNT_CTOR(nsDisplayBoxShadowOuter);
--- a/layout/reftests/backgrounds/reftest.list
+++ b/layout/reftests/backgrounds/reftest.list
@@ -1,19 +1,19 @@
 include gradient/reftest.list
 include vector/reftest.list
 
 random-if(bug685516) == layers-stacking-order.xhtml layers-stacking-order-ref.xhtml
 random-if(bug685516) == layers-layer-count-cascade-1.xhtml layers-layer-count-1-ref.xhtml
 random-if(bug685516) == layers-layer-count-inheritance-1.xhtml layers-layer-count-1-ref.xhtml
 random-if(bug685516) == layers-layer-count-cascade-2.xhtml layers-layer-count-2-ref.xhtml
 random-if(bug685516) == layers-layer-count-inheritance-2.xhtml layers-layer-count-2-ref.xhtml
-== viewport-translucent-color-1.html viewport-translucent-color-ref.html
-fails-if(Android) == viewport-translucent-color-2.html viewport-translucent-color-ref.html
-fails-if(Android) == viewport-translucent-color-3.html viewport-translucent-color-ref.html
+fuzzy-if(Android,9,600000) == viewport-translucent-color-1.html viewport-translucent-color-ref.html
+== viewport-translucent-color-2.html viewport-translucent-color-ref.html
+== viewport-translucent-color-3.html viewport-translucent-color-ref.html
 != viewport-translucent-color-ref.html about:blank
 random-if(bug685516) == iframe-translucent-color-1.html iframe-translucent-color-ref.html
 random-if(bug685516) == translucent-color-1.html translucent-color-ref.html
 random-if(bug685516) == translucent-color-2.html translucent-color-ref.html
 random-if(bug685516) == translucent-color-3.html translucent-color-ref.html
 != translucent-color-ref.html about:blank
 == root-element-display-none-1.html root-element-display-none-ref.html
 random-if(bug685516) == continuous-inline-1a.html continuous-inline-1-ref.html
--- a/layout/reftests/css-gradients/reftest.list
+++ b/layout/reftests/css-gradients/reftest.list
@@ -118,17 +118,17 @@ fails-if(!d2d) == aja-linear-2d.html aja
 fuzzy-if(!contentSameGfxBackendAsCanvas,1,19999) fails-if(Android) == aja-linear-3a.html aja-linear-3-ref.html
 fuzzy-if(!contentSameGfxBackendAsCanvas,1,19999) fails-if(Android) == aja-linear-3b.html aja-linear-3-ref.html
 fuzzy-if(!contentSameGfxBackendAsCanvas,2,20000) fails-if(Android) == aja-linear-4a.html aja-linear-4-ref.html
 fuzzy-if(!contentSameGfxBackendAsCanvas,2,20000) fails-if(Android) == aja-linear-4b.html aja-linear-4-ref.html
 fuzzy-if(!contentSameGfxBackendAsCanvas,2,20000) fails-if(Android) == aja-linear-5a.html aja-linear-5-ref.html
 fuzzy-if(!contentSameGfxBackendAsCanvas,2,16477) fails-if(Android) == aja-linear-6a.html aja-linear-6-ref.html # bug 526708
 fails == aja-linear-6b.html aja-linear-6-ref.html # bug 522607
 == height-dependence-1.html height-dependence-1-ref.html
-fails-if(cocoaWidget) == height-dependence-2.html height-dependence-2-ref.html # bug 535007
+== height-dependence-2.html height-dependence-2-ref.html
 == height-dependence-3.html height-dependence-3-ref.html
 
 fails-if(d2d) == linear-onestopposition-1.html linear-onestopposition-1-ref.html # bug 638664
 == linear-onestopposition-1.html linear-onestopposition-1-ref2.html
 fails-if(d2d) fails-if(cocoaWidget) == radial-onestopposition-1a.html radial-onestopposition-1-ref.html # bug 638664
 fails-if(d2d) fails-if(cocoaWidget) == radial-onestopposition-1b.html radial-onestopposition-1-ref.html # bug 638664
 fails-if(d2d) fails-if(cocoaWidget) == radial-onestopposition-1c.html radial-onestopposition-1-ref.html # bug 638664
 == repeating-linear-onestopposition-1.html orange-square.html