Bug 820246 - Split nsDisplayCanvasBackground into separate color and image items. r=roc
authorMatt Woodrow <mwoodrow@mozilla.com>
Thu, 13 Dec 2012 14:15:55 +1300
changeset 115991 afc699fc7e652428f9dd016b8f921b7426bfcf74
parent 115990 b80437be0e7001991a34d5f7f6a66186c08858bd
child 115992 777fd91b7fda0325d0dc715967fc798fd68dd5ef
push id24034
push useremorley@mozilla.com
push dateFri, 14 Dec 2012 15:28:57 +0000
treeherdermozilla-central@50d8f411d305 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs820246
milestone20.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 820246 - Split nsDisplayCanvasBackground into separate color and image items. r=roc
layout/base/nsDisplayItemTypesList.h
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/base/nsPresShell.cpp
layout/generic/nsCanvasFrame.cpp
layout/generic/nsCanvasFrame.h
layout/reftests/image/reftest.list
--- a/layout/base/nsDisplayItemTypesList.h
+++ b/layout/base/nsDisplayItemTypesList.h
@@ -4,17 +4,18 @@ DECLARE_DISPLAY_ITEM_TYPE_FLAGS(BACKGROU
 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)
-DECLARE_DISPLAY_ITEM_TYPE(CANVAS_BACKGROUND)
+DECLARE_DISPLAY_ITEM_TYPE(CANVAS_BACKGROUND_COLOR)
+DECLARE_DISPLAY_ITEM_TYPE(CANVAS_BACKGROUND_IMAGE)
 DECLARE_DISPLAY_ITEM_TYPE(CANVAS_FOCUS)
 DECLARE_DISPLAY_ITEM_TYPE(CARET)
 DECLARE_DISPLAY_ITEM_TYPE(CHECKED_CHECKBOX)
 DECLARE_DISPLAY_ITEM_TYPE(CHECKED_RADIOBUTTON)
 DECLARE_DISPLAY_ITEM_TYPE(CLIP)
 DECLARE_DISPLAY_ITEM_TYPE(CLIP_ROUNDED_RECT)
 DECLARE_DISPLAY_ITEM_TYPE(COLUMN_RULE)
 DECLARE_DISPLAY_ITEM_TYPE(COMBOBOX_FOCUS)
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -44,16 +44,17 @@
 #include "nsSVGElement.h"
 #include "nsSVGClipPathFrame.h"
 #include "sampler.h"
 #include "nsAnimationManager.h"
 #include "nsTransitionManager.h"
 #include "nsIViewManager.h"
 #include "ImageLayers.h"
 #include "ImageContainer.h"
+#include "nsCanvasFrame.h"
 
 #include "mozilla/StandardInteger.h"
 
 using namespace mozilla;
 using namespace mozilla::css;
 using namespace mozilla::layers;
 using namespace mozilla::dom;
 typedef FrameMetrics::ViewID ViewID;
@@ -2078,24 +2079,32 @@ static void CheckForBorderItem(nsDisplay
       nextItem->GetType() == nsDisplayItem::TYPE_BORDER) {
     aFlags |= nsCSSRendering::PAINTBG_WILL_PAINT_BORDER;
   }
 }
 
 void
 nsDisplayBackgroundImage::Paint(nsDisplayListBuilder* aBuilder,
                                 nsRenderingContext* aCtx) {
-
+  PaintInternal(aBuilder, aCtx, mVisibleRect, nullptr);
+}
+
+void
+nsDisplayBackgroundImage::PaintInternal(nsDisplayListBuilder* aBuilder,
+                                        nsRenderingContext* aCtx, const nsRect& aBounds,
+                                        nsRect* aClipRect) {
   nsPoint offset = ToReferenceFrame();
   uint32_t flags = aBuilder->GetBackgroundPaintFlags();
   CheckForBorderItem(this, flags);
+
   nsCSSRendering::PaintBackground(mFrame->PresContext(), *aCtx, mFrame,
-                                  mVisibleRect,
+                                  aBounds,
                                   nsRect(offset, mFrame->GetSize()),
-                                  flags, nullptr, mLayer);
+                                  flags, aClipRect, mLayer);
+
 }
 
 void nsDisplayBackgroundImage::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                                          const nsDisplayItemGeometry* aGeometry,
                                                          nsRegion* aInvalidRegion)
 {
   if (!mBackgroundStyle) {
     return;
@@ -2144,16 +2153,20 @@ nsDisplayBackgroundImage::GetBoundsInter
     return r + ToReferenceFrame();
   }
 
   if (!mBackgroundStyle) {
     return nsRect();
   }
 
   nsRect borderBox = nsRect(ToReferenceFrame(), mFrame->GetSize());
+  if (mFrame->GetType() == nsGkAtoms::canvasFrame) {
+    nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
+    borderBox = frame->CanvasArea() + ToReferenceFrame();
+  }
   const nsStyleBackground::Layer& layer = mBackgroundStyle->mLayers[mLayer];
   return nsCSSRendering::GetBackgroundLayerRect(presContext, mFrame,
                                                 borderBox, *mBackgroundStyle, layer);
 }
 
 uint32_t
 nsDisplayBackgroundImage::GetPerFrameKey()
 {
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -1908,16 +1908,19 @@ protected:
   typedef class mozilla::layers::ImageLayer ImageLayer;
 
   bool TryOptimizeToImageLayer(LayerManager* aManager, nsDisplayListBuilder* aBuilder);
   bool IsSingleFixedPositionImage(nsDisplayListBuilder* aBuilder,
                                   const nsRect& aClipRect,
                                   gfxRect* aDestRect);
   nsRect GetBoundsInternal();
 
+  void PaintInternal(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx,
+                     const nsRect& aBounds, nsRect* aClipRect);
+
   // Cache the result of nsCSSRendering::FindBackground. Always null if
   // mIsThemed is true or if FindBackground returned false.
   const nsStyleBackground* mBackgroundStyle;
   /* If this background can be a simple image layer, we store the format here. */
   nsRefPtr<ImageContainer> mImageContainer;
   gfxRect mDestRect;
   /* Bounds of this display item */
   nsRect mBounds;
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -4826,18 +4826,18 @@ PresShell::AddPrintPreviewBackgroundItem
 }
 
 static bool
 AddCanvasBackgroundColor(const nsDisplayList& aList, nsIFrame* aCanvasFrame,
                          nscolor aColor)
 {
   for (nsDisplayItem* i = aList.GetBottom(); i; i = i->GetAbove()) {
     if (i->GetUnderlyingFrame() == aCanvasFrame &&
-        i->GetType() == nsDisplayItem::TYPE_CANVAS_BACKGROUND) {
-      nsDisplayCanvasBackground* bg = static_cast<nsDisplayCanvasBackground*>(i);
+        i->GetType() == nsDisplayItem::TYPE_CANVAS_BACKGROUND_COLOR) {
+      nsDisplayCanvasBackgroundColor* bg = static_cast<nsDisplayCanvasBackgroundColor*>(i);
       bg->SetExtraBackgroundColor(aColor);
       return true;
     }
     nsDisplayList* sublist = i->GetSameCoordinateSystemChildren();
     if (sublist && AddCanvasBackgroundColor(*sublist, aCanvasFrame, aColor))
       return true;
   }
   return false;
--- a/layout/generic/nsCanvasFrame.cpp
+++ b/layout/generic/nsCanvasFrame.cpp
@@ -173,40 +173,47 @@ nsRect nsCanvasFrame::CanvasArea() const
   nsIScrollableFrame *scrollableFrame = do_QueryFrame(GetParent());
   if (scrollableFrame) {
     nsRect portRect = scrollableFrame->GetScrollPortRect();
     result.UnionRect(result, nsRect(nsPoint(0, 0), portRect.Size()));
   }
   return result;
 }
 
+void
+nsDisplayCanvasBackgroundColor::Paint(nsDisplayListBuilder* aBuilder,
+                                      nsRenderingContext* aCtx)
+{
+  nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
+  nsPoint offset = ToReferenceFrame();
+  nsRect bgClipRect = frame->CanvasArea() + offset;
+  if (NS_GET_A(mColor) > 0) {
+    aCtx->SetColor(mColor);
+    aCtx->FillRect(bgClipRect);
+  }
+}
+
 static void BlitSurface(gfxContext* aDest, const gfxRect& aRect, gfxASurface* aSource)
 {
   aDest->Translate(gfxPoint(aRect.x, aRect.y));
   aDest->SetSource(aSource);
   aDest->NewPath();
   aDest->Rectangle(gfxRect(0, 0, aRect.width, aRect.height));
   aDest->Fill();
   aDest->Translate(-gfxPoint(aRect.x, aRect.y));
 }
 
 void
-nsDisplayCanvasBackground::Paint(nsDisplayListBuilder* aBuilder,
-                                 nsRenderingContext* aCtx)
+nsDisplayCanvasBackgroundImage::Paint(nsDisplayListBuilder* aBuilder,
+                                      nsRenderingContext* aCtx)
 {
   nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
   nsPoint offset = ToReferenceFrame();
   nsRect bgClipRect = frame->CanvasArea() + offset;
-  if (mIsBottommostLayer && NS_GET_A(mExtraBackgroundColor) > 0) {
-    aCtx->SetColor(mExtraBackgroundColor);
-    aCtx->FillRect(bgClipRect);
-  }
 
-  bool snap;
-  nsRect bounds = GetBounds(aBuilder, &snap);
   nsRenderingContext context;
   nsRefPtr<gfxContext> dest = aCtx->ThebesContext();
   nsRefPtr<gfxASurface> surf;
   nsRefPtr<gfxContext> ctx;
   gfxRect destRect;
 #ifndef MOZ_GFX_OPTIMIZE_MOBILE
   if (IsSingleFixedPositionImage(aBuilder, bgClipRect, &destRect) &&
       aBuilder->IsPaintingToWindow() && !aBuilder->IsCompositingCheap() &&
@@ -225,25 +232,24 @@ nsDisplayCanvasBackground::Paint(nsDispl
     if (surf) {
       ctx = new gfxContext(surf);
       ctx->Translate(-gfxPoint(destRect.x, destRect.y));
       context.Init(aCtx->DeviceContext(), ctx);
     }
   }
 #endif
 
-  nsCSSRendering::PaintBackground(mFrame->PresContext(), surf ? context : *aCtx, mFrame,
-                                  surf ? bounds : mVisibleRect,
-                                  nsRect(offset, mFrame->GetSize()),
-                                  aBuilder->GetBackgroundPaintFlags(),
-                                  &bgClipRect, mLayer);
+  PaintInternal(aBuilder,
+                surf ? &context : aCtx,
+                surf ? bgClipRect: mVisibleRect,
+                &bgClipRect);
+
   if (surf) {
     BlitSurface(dest, destRect, surf);
-
-    GetUnderlyingFrame()->Properties().Set(nsIFrame::CachedBackgroundImage(), surf.forget().get());
+    frame->Properties().Set(nsIFrame::CachedBackgroundImage(), surf.forget().get());
   }
 }
 
 /**
  * A display item to paint the focus ring for the document.
  *
  * The only reason this can't use nsDisplayGeneric is overriding GetBounds.
  */
@@ -297,21 +303,24 @@ nsCanvasFrame::BuildDisplayList(nsDispla
   if (IsVisibleForPainting(aBuilder)) {
     nsStyleContext* bgSC;
     const nsStyleBackground* bg = nullptr;
     bool isThemed = IsThemed();
     if (!isThemed &&
         nsCSSRendering::FindBackground(PresContext(), this, &bgSC)) {
       bg = bgSC->GetStyleBackground();
     }
+    aLists.BorderBackground()->AppendNewToTop(
+        new (aBuilder) nsDisplayCanvasBackgroundColor(aBuilder, this));
+
     // Create separate items for each background layer.
     NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) {
       rv = aLists.BorderBackground()->AppendNewToTop(
-          new (aBuilder) nsDisplayCanvasBackground(aBuilder, this, i,
-                                                   isThemed, bg));
+          new (aBuilder) nsDisplayCanvasBackgroundImage(aBuilder, this, i,
+                                                        isThemed, bg));
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
   nsIFrame* kid;
   for (kid = GetFirstPrincipalChild(); kid; kid = kid->GetNextSibling()) {
     // Put our child into its own pseudo-stack.
     rv = BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
--- a/layout/generic/nsCanvasFrame.h
+++ b/layout/generic/nsCanvasFrame.h
@@ -117,91 +117,94 @@ protected:
 };
 
 /**
  * Override nsDisplayBackground methods so that we pass aBGClipRect to
  * PaintBackground, covering the whole overflow area.
  * We can also paint an "extra background color" behind the normal
  * background.
  */
-class nsDisplayCanvasBackground : public nsDisplayBackgroundImage {
+class nsDisplayCanvasBackgroundColor : public nsDisplayItem {
 public:
-  nsDisplayCanvasBackground(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame,
-                            uint32_t aLayer, bool aIsThemed,
-                            const nsStyleBackground* aBackgroundStyle)
-    : nsDisplayBackgroundImage(aBuilder, aFrame, aLayer, aIsThemed, aBackgroundStyle),
-      mExtraBackgroundColor(NS_RGBA(0,0,0,0))
+  nsDisplayCanvasBackgroundColor(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame)
+    : nsDisplayItem(aBuilder, aFrame)
+    , mColor(NS_RGBA(0,0,0,0))
   {
   }
 
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                  nsRegion* aVisibleRegion,
                                  const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE
   {
-    return NS_GET_A(mExtraBackgroundColor) > 0 ||
-      nsDisplayBackgroundImage::ComputeVisibility(aBuilder, aVisibleRegion,
-                                             aAllowVisibleRegionExpansion);
+    return NS_GET_A(mColor) > 0;
   }
   virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
                                    bool* aSnap) MOZ_OVERRIDE
   {
-    if (NS_GET_A(mExtraBackgroundColor) == 255) {
+    if (NS_GET_A(mColor) == 255) {
       return nsRegion(GetBounds(aBuilder, aSnap));
     }
-    return nsDisplayBackgroundImage::GetOpaqueRegion(aBuilder, aSnap);
+    return nsRegion();
   }
   virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) MOZ_OVERRIDE
   {
-    nscolor background;
-    if (!nsDisplayBackgroundImage::IsUniform(aBuilder, &background))
-      return false;
-    NS_ASSERTION(background == NS_RGBA(0,0,0,0),
-                 "The nsDisplayBackground for a canvas frame doesn't paint "
-                 "its background color normally");
-    *aColor = mExtraBackgroundColor;
+    *aColor = mColor;
     return true;
   }
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE
   {
     nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
     *aSnap = true;
     return frame->CanvasArea() + ToReferenceFrame();
   }
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) MOZ_OVERRIDE
   {
     // We need to override so we don't consider border-radius.
     aOutFrames->AppendElement(mFrame);
   }
-  virtual bool ShouldFixToViewport(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE
-  {
-    // Put background-attachment:fixed canvas background images in their own
-    // compositing layer. Since we know their background painting area can't
-    // change (unless the viewport size itself changes), async scrolling
-    // will work well.
-    return mBackgroundStyle &&
-      mBackgroundStyle->mLayers[mLayer].mAttachment == NS_STYLE_BG_ATTACHMENT_FIXED &&
-      !mBackgroundStyle->mLayers[mLayer].mImage.IsEmpty();
-  }
   virtual void NotifyRenderingChanged() MOZ_OVERRIDE
   {
     mFrame->Properties().Delete(nsIFrame::CachedBackgroundImage());
   }
 
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx) MOZ_OVERRIDE;
- 
-  // We still need to paint a background color as well as an image for this item, 
-  // so we can't support this yet.
-  virtual bool SupportsOptimizingToImage() { return false; }
 
   void SetExtraBackgroundColor(nscolor aColor)
   {
-    mExtraBackgroundColor = aColor;
+    mColor = aColor;
   }
 
-  NS_DISPLAY_DECL_NAME("CanvasBackground", TYPE_CANVAS_BACKGROUND)
+  NS_DISPLAY_DECL_NAME("CanvasBackgroundColor", TYPE_CANVAS_BACKGROUND_COLOR)
 
 private:
-  nscolor mExtraBackgroundColor;
+  nscolor mColor;
+};
+
+class nsDisplayCanvasBackgroundImage : public nsDisplayBackgroundImage {
+public:
+  nsDisplayCanvasBackgroundImage(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+                                 uint32_t aLayer, bool aIsThemed, const nsStyleBackground* aBg)
+    : nsDisplayBackgroundImage(aBuilder, aFrame, aLayer, aIsThemed, aBg)
+  {}
+
+  virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE;
+
+  virtual bool ShouldFixToViewport(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE
+  {
+    // Put background-attachment:fixed canvas background images in their own
+    // compositing layer. Since we know their background painting area can't
+    // change (unless the viewport size itself changes), async scrolling
+    // will work well.
+    return mBackgroundStyle->mLayers[mLayer].mAttachment == NS_STYLE_BG_ATTACHMENT_FIXED &&
+           !mBackgroundStyle->mLayers[mLayer].mImage.IsEmpty();
+  }
+ 
+  // We still need to paint a background color as well as an image for this item, 
+  // so we can't support this yet.
+  virtual bool SupportsOptimizingToImage() MOZ_OVERRIDE { return false; }
+  
+  
+  NS_DISPLAY_DECL_NAME("CanvasBackgroundImage", TYPE_CANVAS_BACKGROUND_IMAGE)
 };
 
 #endif /* nsCanvasFrame_h___ */
--- a/layout/reftests/image/reftest.list
+++ b/layout/reftests/image/reftest.list
@@ -1,9 +1,9 @@
-random-if(bug685516) == background-image-zoom-1.html background-image-zoom-1-ref.html
+random-if(bug685516) fuzzy-if(Android,4,15) == background-image-zoom-1.html background-image-zoom-1-ref.html
 == background-image-zoom-2.html about:blank
 == image-zoom-1.html image-zoom-1-ref.html
 == image-zoom-2.html image-zoom-1-ref.html
 == invalid-url-image-1.html invalid-url-image-1-ref.html
 == sync-image-switch-1a.html sync-image-switch-1-ref.html
 == sync-image-switch-1b.html sync-image-switch-1-ref.html
 == sync-image-switch-1c.html sync-image-switch-1-ref.html
 == sync-image-switch-1d.html sync-image-switch-1-ref.html