Bug 916034 - Use a similar surface rather than an image surface for the canvas background cache when using azure. r=ajones
authorMatt Woodrow <mwoodrow@mozilla.com>
Wed, 02 Oct 2013 22:12:34 +1300
changeset 149622 ad70d9583d42cfd0ccf8d980c9303e34ccdc5a77
parent 149621 91690a35f26d72bb3aa34faa9fabf3577435fa20
child 149623 2f189d31161d9072358a5544833fb3458a26e030
push idunknown
push userunknown
push dateunknown
reviewersajones
bugs916034
milestone27.0a1
Bug 916034 - Use a similar surface rather than an image surface for the canvas background cache when using azure. r=ajones
layout/generic/nsCanvasFrame.cpp
layout/generic/nsCanvasFrame.h
layout/generic/nsFrame.cpp
layout/generic/nsIFrame.h
--- a/layout/generic/nsCanvasFrame.cpp
+++ b/layout/generic/nsCanvasFrame.cpp
@@ -23,16 +23,17 @@
 #ifdef DEBUG_CANVAS_FOCUS
 #include "nsIDocShell.h"
 #endif
 
 //#define DEBUG_CANVAS_FOCUS
 
 using namespace mozilla;
 using namespace mozilla::layout;
+using namespace mozilla::gfx;
 
 nsIFrame*
 NS_NewCanvasFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsCanvasFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsCanvasFrame)
@@ -193,80 +194,89 @@ static void BlitSurface(gfxContext* aDes
   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));
 }
 
+static void BlitSurface(DrawTarget* aDest, const gfxRect& aRect, DrawTarget* aSource)
+{
+  RefPtr<SourceSurface> source = aSource->Snapshot();
+  aDest->DrawSurface(source,
+                     Rect(aRect.x, aRect.y, aRect.width, aRect.height),
+                     Rect(0, 0, aRect.width, aRect.height));
+}
+
 void
 nsDisplayCanvasBackgroundImage::Paint(nsDisplayListBuilder* aBuilder,
                                       nsRenderingContext* aCtx)
 {
   nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
   nsPoint offset = ToReferenceFrame();
   nsRect bgClipRect = frame->CanvasArea() + offset;
 
   nsRenderingContext context;
   nsRefPtr<gfxContext> dest = aCtx->ThebesContext();
   nsRefPtr<gfxASurface> surf;
+  RefPtr<DrawTarget> dt;
   nsRefPtr<gfxContext> ctx;
   gfxRect destRect;
 #ifndef MOZ_GFX_OPTIMIZE_MOBILE
   if (IsSingleFixedPositionImage(aBuilder, bgClipRect, &destRect) &&
       aBuilder->IsPaintingToWindow() && !aBuilder->IsCompositingCheap() &&
       !dest->CurrentMatrix().HasNonIntegerTranslation()) {
     // Snap image rectangle to nearest pixel boundaries. This is the right way
     // to snap for this context, because we checked HasNonIntegerTranslation above.
     destRect.Round();
-    surf = static_cast<gfxASurface*>(Frame()->Properties().Get(nsIFrame::CachedBackgroundImage()));
     if (dest->IsCairo()) {
+      surf = static_cast<gfxASurface*>(Frame()->Properties().Get(nsIFrame::CachedBackgroundImage()));
       nsRefPtr<gfxASurface> destSurf = dest->CurrentSurface();
       if (surf && surf->GetType() == destSurf->GetType()) {
         BlitSurface(dest, destRect, surf);
         return;
       }
       surf = destSurf->CreateSimilarSurface(
           GFX_CONTENT_COLOR_ALPHA,
           gfxIntSize(ceil(destRect.width), ceil(destRect.height)));
     } else {
+      dt = static_cast<DrawTarget*>(Frame()->Properties().Get(nsIFrame::CachedBackgroundImageDT()));
+      DrawTarget* destDT = dest->GetDrawTarget();
+      if (dt) {
+        BlitSurface(destDT, destRect, dt);
+        return;
+      }
+      dt = destDT->CreateSimilarDrawTarget(IntSize(ceil(destRect.width), ceil(destRect.height)), FORMAT_B8G8R8A8);
+    }
+    if (surf || dt) {
       if (surf) {
-        mozilla::gfx::DrawTarget* dt = dest->GetDrawTarget();
-        mozilla::RefPtr<mozilla::gfx::SourceSurface> source =
-            gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, surf);
-        if (source) {
-          // Could be non-integer pixel alignment
-          dt->DrawSurface(source,
-                          mozilla::gfx::Rect(destRect.x, destRect.y, destRect.width, destRect.height),
-                          mozilla::gfx::Rect(0, 0, destRect.width, destRect.height));
-          return;
-        }
+        ctx = new gfxContext(surf);
+      } else {
+        ctx = new gfxContext(dt);
       }
-      surf = gfxPlatform::GetPlatform()->CreateOffscreenImageSurface(
-          gfxIntSize(ceil(destRect.width), ceil(destRect.height)),
-          GFX_CONTENT_COLOR_ALPHA);
-    }
-    if (surf) {
-      ctx = new gfxContext(surf);
       ctx->Translate(-gfxPoint(destRect.x, destRect.y));
       context.Init(aCtx->DeviceContext(), ctx);
     }
   }
 #endif
 
   PaintInternal(aBuilder,
-                surf ? &context : aCtx,
-                surf ? bgClipRect: mVisibleRect,
+                (surf || dt) ? &context : aCtx,
+                (surf || dt) ? bgClipRect: mVisibleRect,
                 &bgClipRect);
 
   if (surf) {
     BlitSurface(dest, destRect, surf);
     frame->Properties().Set(nsIFrame::CachedBackgroundImage(), surf.forget().get());
   }
+  if (dt) {
+    BlitSurface(dest->GetDrawTarget(), destRect, dt);
+    frame->Properties().Set(nsIFrame::CachedBackgroundImageDT(), dt.forget().drop());
+  }
 }
 
 void
 nsDisplayCanvasThemedBackground::Paint(nsDisplayListBuilder* aBuilder,
                                        nsRenderingContext* aCtx)
 {
   nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
   nsPoint offset = ToReferenceFrame();
--- a/layout/generic/nsCanvasFrame.h
+++ b/layout/generic/nsCanvasFrame.h
@@ -170,16 +170,17 @@ public:
   {
     const nsDisplayItemBoundsGeometry* geometry = static_cast<const nsDisplayItemBoundsGeometry*>(aGeometry);
     ComputeInvalidationRegionDifference(aBuilder, geometry, aInvalidRegion);
   }
 
   virtual void NotifyRenderingChanged() MOZ_OVERRIDE
   {
     mFrame->Properties().Delete(nsIFrame::CachedBackgroundImage());
+    mFrame->Properties().Delete(nsIFrame::CachedBackgroundImageDT());
   }
 
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx) MOZ_OVERRIDE;
 
   void SetExtraBackgroundColor(nscolor aColor)
   {
     mColor = aColor;
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -8214,16 +8214,22 @@ nsIFrame::IsSelected() const
 
 void
 nsIFrame::DestroySurface(void* aPropertyValue)
 {
   static_cast<gfxASurface*>(aPropertyValue)->Release();
 }
 
 void
+nsIFrame::DestroyDT(void* aPropertyValue)
+{
+  static_cast<mozilla::gfx::DrawTarget*>(aPropertyValue)->Release();
+}
+
++void
 nsIFrame::DestroyRegion(void* aPropertyValue)
 {
   delete static_cast<nsRegion*>(aPropertyValue);
 }
 
 bool
 nsIFrame::IsPseudoStackingContextFromStyle() {
   const nsStyleDisplay* disp = StyleDisplay();
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -938,16 +938,17 @@ public:
   }
 
   static void DestroyOverflowAreas(void* aPropertyValue)
   {
     delete static_cast<nsOverflowAreas*>(aPropertyValue);
   }
 
   static void DestroySurface(void* aPropertyValue);
+  static void DestroyDT(void* aPropertyValue);
 
 #ifdef _MSC_VER
 // XXX Workaround MSVC issue by making the static FramePropertyDescriptor
 // non-const.  See bug 555727.
 #define NS_PROPERTY_DESCRIPTOR_CONST
 #else
 #define NS_PROPERTY_DESCRIPTOR_CONST const
 #endif
@@ -984,16 +985,17 @@ public:
   NS_DECLARE_FRAME_PROPERTY(UsedPaddingProperty, DestroyMargin)
   NS_DECLARE_FRAME_PROPERTY(UsedBorderProperty, DestroyMargin)
 
   NS_DECLARE_FRAME_PROPERTY(ScrollLayerCount, nullptr)
 
   NS_DECLARE_FRAME_PROPERTY(LineBaselineOffset, nullptr)
 
   NS_DECLARE_FRAME_PROPERTY(CachedBackgroundImage, DestroySurface)
+  NS_DECLARE_FRAME_PROPERTY(CachedBackgroundImageDT, DestroyDT)
 
   NS_DECLARE_FRAME_PROPERTY(InvalidationRect, DestroyRect)
 
   /**
    * Return the distance between the border edge of the frame and the
    * margin edge of the frame.  Like GetRect(), returns the dimensions
    * as of the most recent reflow.
    *