Bug 1209705 - Propagate the DrawResult for temporary surfaces to the caller in ClippedImage. r=tn
authorSeth Fowler <mark.seth.fowler@gmail.com>
Thu, 01 Oct 2015 11:31:41 -0700
changeset 265630 4d2c675a88302e9796334b53181260bce9fb1635
parent 265629 a473909f575931f67e836ae17dd739f480275e85
child 265631 ba3a9ec11d89c6b779f2db12a384e7e0cb22a724
push id15472
push usercbook@mozilla.com
push dateFri, 02 Oct 2015 11:51:34 +0000
treeherderfx-team@2c33ef6b27e0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstn
bugs1209705
milestone44.0a1
Bug 1209705 - Propagate the DrawResult for temporary surfaces to the caller in ClippedImage. r=tn
image/ClippedImage.cpp
image/ClippedImage.h
--- a/image/ClippedImage.cpp
+++ b/image/ClippedImage.cpp
@@ -6,17 +6,20 @@
 #include <new>      // Workaround for bug in VS10; see bug 981264.
 #include <cmath>
 #include <utility>
 
 #include "gfxDrawable.h"
 #include "gfxPlatform.h"
 #include "gfxUtils.h"
 #include "mozilla/gfx/2D.h"
+#include "mozilla/Move.h"
 #include "mozilla/RefPtr.h"
+#include "mozilla/Pair.h"
+#include "mozilla/Tuple.h"
 
 #include "ImageRegion.h"
 #include "Orientation.h"
 #include "SVGImageContext.h"
 
 #include "ClippedImage.h"
 
 namespace mozilla {
@@ -32,92 +35,110 @@ namespace image {
 
 class ClippedImageCachedSurface
 {
 public:
   ClippedImageCachedSurface(already_AddRefed<SourceSurface> aSurface,
                             const nsIntSize& aSize,
                             const Maybe<SVGImageContext>& aSVGContext,
                             float aFrame,
-                            uint32_t aFlags)
+                            uint32_t aFlags,
+                            DrawResult aDrawResult)
     : mSurface(aSurface)
     , mSize(aSize)
+    , mSVGContext(aSVGContext)
     , mFrame(aFrame)
     , mFlags(aFlags)
+    , mDrawResult(aDrawResult)
   {
     MOZ_ASSERT(mSurface, "Must have a valid surface");
-    if (aSVGContext) {
-      mSVGContext.emplace(*aSVGContext);
-    }
   }
 
   bool Matches(const nsIntSize& aSize,
                const Maybe<SVGImageContext>& aSVGContext,
                float aFrame,
-               uint32_t aFlags)
+               uint32_t aFlags) const
   {
     return mSize == aSize &&
            mSVGContext == aSVGContext &&
            mFrame == aFrame &&
            mFlags == aFlags;
   }
 
-  already_AddRefed<SourceSurface> Surface() {
+  already_AddRefed<SourceSurface> Surface() const
+  {
     RefPtr<SourceSurface> surf(mSurface);
     return surf.forget();
   }
 
+  DrawResult GetDrawResult() const
+  {
+    return mDrawResult;
+  }
+
+  bool NeedsRedraw() const
+  {
+    return mDrawResult != DrawResult::SUCCESS &&
+           mDrawResult != DrawResult::BAD_IMAGE;
+  }
+
 private:
   RefPtr<SourceSurface>  mSurface;
   const nsIntSize        mSize;
   Maybe<SVGImageContext> mSVGContext;
   const float            mFrame;
   const uint32_t         mFlags;
+  const DrawResult       mDrawResult;
 };
 
 class DrawSingleTileCallback : public gfxDrawingCallback
 {
 public:
   DrawSingleTileCallback(ClippedImage* aImage,
                          const nsIntSize& aSize,
                          const Maybe<SVGImageContext>& aSVGContext,
                          uint32_t aWhichFrame,
                          uint32_t aFlags)
     : mImage(aImage)
     , mSize(aSize)
     , mSVGContext(aSVGContext)
     , mWhichFrame(aWhichFrame)
     , mFlags(aFlags)
+    , mDrawResult(DrawResult::NOT_READY)
   {
     MOZ_ASSERT(mImage, "Must have an image to clip");
   }
 
   virtual bool operator()(gfxContext* aContext,
                           const gfxRect& aFillRect,
                           const GraphicsFilter& aFilter,
                           const gfxMatrix& aTransform)
   {
     MOZ_ASSERT(aTransform.IsIdentity(),
                "Caller is probably CreateSamplingRestrictedDrawable, "
                "which should not happen");
 
     // Draw the image. |gfxCallbackDrawable| always calls this function with
     // arguments that guarantee we never tile.
-    mImage->DrawSingleTile(aContext, mSize, ImageRegion::Create(aFillRect),
-                           mWhichFrame, aFilter, mSVGContext, mFlags);
+    mDrawResult =
+      mImage->DrawSingleTile(aContext, mSize, ImageRegion::Create(aFillRect),
+                             mWhichFrame, aFilter, mSVGContext, mFlags);
 
     return true;
   }
 
+  DrawResult GetDrawResult() { return mDrawResult; }
+
 private:
   nsRefPtr<ClippedImage>        mImage;
   const nsIntSize               mSize;
   const Maybe<SVGImageContext>& mSVGContext;
   const uint32_t                mWhichFrame;
   const uint32_t                mFlags;
+  DrawResult                    mDrawResult;
 };
 
 ClippedImage::ClippedImage(Image* aImage,
                            nsIntRect aClip)
   : ImageWrapper(aImage)
   , mClip(aClip)
 {
   MOZ_ASSERT(aImage != nullptr, "ClippedImage requires an existing Image");
@@ -212,76 +233,82 @@ ClippedImage::GetIntrinsicRatio(nsSize* 
   *aRatio = nsSize(mClip.width, mClip.height);
   return NS_OK;
 }
 
 NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
 ClippedImage::GetFrame(uint32_t aWhichFrame,
                        uint32_t aFlags)
 {
-  return GetFrameInternal(mClip.Size(), Nothing(), aWhichFrame, aFlags);
+  DrawResult result;
+  RefPtr<SourceSurface> surface;
+  Tie(result, surface) = GetFrameInternal(mClip.Size(), Nothing(), aWhichFrame, aFlags);
+  return surface.forget();
 }
 
 NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
 ClippedImage::GetFrameAtSize(const IntSize& aSize,
                              uint32_t aWhichFrame,
                              uint32_t aFlags)
 {
   // XXX(seth): It'd be nice to support downscale-during-decode for this case,
   // but right now we just fall back to the intrinsic size.
   return GetFrame(aWhichFrame, aFlags);
 }
 
-already_AddRefed<SourceSurface>
+Pair<DrawResult, RefPtr<SourceSurface>>
 ClippedImage::GetFrameInternal(const nsIntSize& aSize,
                                const Maybe<SVGImageContext>& aSVGContext,
                                uint32_t aWhichFrame,
                                uint32_t aFlags)
 {
   if (!ShouldClip()) {
-    return InnerImage()->GetFrame(aWhichFrame, aFlags);
+    RefPtr<SourceSurface> surface = InnerImage()->GetFrame(aWhichFrame, aFlags);
+    return MakePair(surface ? DrawResult::SUCCESS : DrawResult::NOT_READY,
+                    Move(surface));
   }
 
   float frameToDraw = InnerImage()->GetFrameIndex(aWhichFrame);
-  if (!mCachedSurface || !mCachedSurface->Matches(aSize,
-                                                  aSVGContext,
-                                                  frameToDraw,
-                                                  aFlags)) {
+  if (!mCachedSurface ||
+      !mCachedSurface->Matches(aSize, aSVGContext, frameToDraw, aFlags) ||
+      mCachedSurface->NeedsRedraw()) {
     // Create a surface to draw into.
     RefPtr<DrawTarget> target = gfxPlatform::GetPlatform()->
       CreateOffscreenContentDrawTarget(IntSize(aSize.width, aSize.height),
                                        SurfaceFormat::B8G8R8A8);
     if (!target) {
       NS_ERROR("Could not create a DrawTarget");
-      return nullptr;
+      return MakePair(DrawResult::TEMPORARY_ERROR, RefPtr<SourceSurface>());
     }
 
     nsRefPtr<gfxContext> ctx = new gfxContext(target);
 
     // Create our callback.
-    nsRefPtr<gfxDrawingCallback> drawTileCallback =
+    nsRefPtr<DrawSingleTileCallback> drawTileCallback =
       new DrawSingleTileCallback(this, aSize, aSVGContext, aWhichFrame, aFlags);
     nsRefPtr<gfxDrawable> drawable =
       new gfxCallbackDrawable(drawTileCallback, aSize);
 
     // Actually draw. The callback will end up invoking DrawSingleTile.
     gfxUtils::DrawPixelSnapped(ctx, drawable, aSize,
                                ImageRegion::Create(aSize),
                                SurfaceFormat::B8G8R8A8,
                                GraphicsFilter::FILTER_FAST,
                                imgIContainer::FLAG_CLAMP);
 
     // Cache the resulting surface.
-    mCachedSurface = new ClippedImageCachedSurface(target->Snapshot(), aSize,
-                                                   aSVGContext, frameToDraw,
-                                                   aFlags);
+    mCachedSurface =
+      new ClippedImageCachedSurface(target->Snapshot(), aSize, aSVGContext,
+                                    frameToDraw, aFlags,
+                                    drawTileCallback->GetDrawResult());
   }
 
   MOZ_ASSERT(mCachedSurface, "Should have a cached surface now");
-  return mCachedSurface->Surface();
+  RefPtr<SourceSurface> surface = mCachedSurface->Surface();
+  return MakePair(mCachedSurface->GetDrawResult(), Move(surface));
 }
 
 NS_IMETHODIMP_(bool)
 ClippedImage::IsImageContainerAvailable(LayerManager* aManager, uint32_t aFlags)
 {
   if (!ShouldClip()) {
     return InnerImage()->IsImageContainerAvailable(aManager, aFlags);
   }
@@ -332,31 +359,34 @@ ClippedImage::Draw(gfxContext* aContext,
                               aFilter, aSVGContext, aFlags);
   }
 
   // Check for tiling. If we need to tile then we need to create a
   // gfxCallbackDrawable to handle drawing for us.
   if (MustCreateSurface(aContext, aSize, aRegion, aFlags)) {
     // Create a temporary surface containing a single tile of this image.
     // GetFrame will call DrawSingleTile internally.
-    RefPtr<SourceSurface> surface =
+    DrawResult result;
+    RefPtr<SourceSurface> surface;
+    Tie(result, surface) =
       GetFrameInternal(aSize, aSVGContext, aWhichFrame, aFlags);
     if (!surface) {
-      return DrawResult::TEMPORARY_ERROR;
+      MOZ_ASSERT(result != DrawResult::SUCCESS);
+      return result;
     }
 
     // Create a drawable from that surface.
     nsRefPtr<gfxSurfaceDrawable> drawable =
       new gfxSurfaceDrawable(surface, aSize);
 
     // Draw.
     gfxUtils::DrawPixelSnapped(aContext, drawable, aSize, aRegion,
                                SurfaceFormat::B8G8R8A8, aFilter);
 
-    return DrawResult::SUCCESS;
+    return result;
   }
 
   return DrawSingleTile(aContext, aSize, aRegion, aWhichFrame,
                         aFilter, aSVGContext, aFlags);
 }
 
 static SVGImageContext
 UnclipViewport(const SVGImageContext& aOldContext,
--- a/image/ClippedImage.h
+++ b/image/ClippedImage.h
@@ -63,17 +63,17 @@ public:
                                     uint32_t aFlags) override;
 
 protected:
   ClippedImage(Image* aImage, nsIntRect aClip);
 
   virtual ~ClippedImage();
 
 private:
-  already_AddRefed<SourceSurface>
+  Pair<DrawResult, RefPtr<SourceSurface>>
     GetFrameInternal(const nsIntSize& aSize,
                      const Maybe<SVGImageContext>& aSVGContext,
                      uint32_t aWhichFrame,
                      uint32_t aFlags);
   bool ShouldClip();
   DrawResult DrawSingleTile(gfxContext* aContext,
                             const nsIntSize& aSize,
                             const ImageRegion& aRegion,