Bug 1296147 (Part 1) - Add a DrawableSurface smart pointer type to allow lazy surface generation. r=dholbert,edwin
authorSeth Fowler <mark.seth.fowler@gmail.com>
Wed, 17 Aug 2016 17:50:31 -0700
changeset 402958 0f9b465ebb5fab7f1dd2d7eb32e172292a618b21
parent 402957 96766f088fd33489b6b8011cc685eb09fabb0d19
child 402959 e7caba6197ba3500be336d88ca2571aa6c0b8192
push id26791
push userbmo:mh+mozilla@glandium.org
push dateFri, 19 Aug 2016 00:08:51 +0000
reviewersdholbert, edwin
bugs1296147
milestone51.0a1
Bug 1296147 (Part 1) - Add a DrawableSurface smart pointer type to allow lazy surface generation. r=dholbert,edwin
image/DecodedSurfaceProvider.h
image/FrameAnimator.cpp
image/ISurfaceProvider.h
image/LookupResult.h
image/RasterImage.cpp
image/RasterImage.h
image/SurfaceCache.cpp
image/SurfaceCache.h
image/VectorImage.cpp
--- a/image/DecodedSurfaceProvider.h
+++ b/image/DecodedSurfaceProvider.h
@@ -33,21 +33,21 @@ public:
                          const SurfaceKey& aSurfaceKey);
 
 
   //////////////////////////////////////////////////////////////////////////////
   // ISurfaceProvider implementation.
   //////////////////////////////////////////////////////////////////////////////
 
 public:
-  DrawableFrameRef DrawableRef() override;
   bool IsFinished() const override;
   size_t LogicalSizeInBytes() const override;
 
 protected:
+  DrawableFrameRef DrawableRef() override;
   bool IsLocked() const override { return bool(mLockRef); }
   void SetLocked(bool aLocked) override;
 
 
   //////////////////////////////////////////////////////////////////////////////
   // IDecodingTask implementation.
   //////////////////////////////////////////////////////////////////////////////
 
--- a/image/FrameAnimator.cpp
+++ b/image/FrameAnimator.cpp
@@ -296,27 +296,28 @@ FrameAnimator::RequestRefresh(AnimationS
 
 LookupResult
 FrameAnimator::GetCompositedFrame(uint32_t aFrameNum)
 {
   MOZ_ASSERT(aFrameNum != 0, "First frame is never composited");
 
   // If we have a composited version of this frame, return that.
   if (mLastCompositedFrameIndex == int32_t(aFrameNum)) {
-    return LookupResult(mCompositingFrame->DrawableRef(), MatchType::EXACT);
+    return LookupResult(DrawableSurface(mCompositingFrame->DrawableRef()),
+                        MatchType::EXACT);
   }
 
   // Otherwise return the raw frame. DoBlend is required to ensure that we only
   // hit this case if the frame is not paletted and doesn't require compositing.
   LookupResult result =
     SurfaceCache::Lookup(ImageKey(mImage),
                          RasterSurfaceKey(mSize,
                                           DefaultSurfaceFlags(),
                                           aFrameNum));
-  MOZ_ASSERT(!result || !result.DrawableRef()->GetIsPaletted(),
+  MOZ_ASSERT(!result || !result.Surface()->GetIsPaletted(),
              "About to return a paletted frame");
   return result;
 }
 
 FrameTimeout
 FrameAnimator::GetTimeoutForFrame(uint32_t aFrameNum) const
 {
   RawAccessFrameRef frame = GetRawFrame(aFrameNum);
@@ -376,17 +377,17 @@ FrameAnimator::CollectSizeOfCompositingS
 RawAccessFrameRef
 FrameAnimator::GetRawFrame(uint32_t aFrameNum) const
 {
   LookupResult result =
     SurfaceCache::Lookup(ImageKey(mImage),
                          RasterSurfaceKey(mSize,
                                           DefaultSurfaceFlags(),
                                           aFrameNum));
-  return result ? result.DrawableRef()->RawAccessRef()
+  return result ? result.Surface()->RawAccessRef()
                 : RawAccessFrameRef();
 }
 
 //******************************************************************************
 // DoBlend gets called when the timer for animation get fired and we have to
 // update the composited frame of the animation.
 bool
 FrameAnimator::DoBlend(IntRect* aDirtyRect,
--- a/image/ISurfaceProvider.h
+++ b/image/ISurfaceProvider.h
@@ -6,44 +6,46 @@
 /**
  * An interface for objects which can either store a surface or dynamically
  * generate one, and various implementations.
  */
 
 #ifndef mozilla_image_ISurfaceProvider_h
 #define mozilla_image_ISurfaceProvider_h
 
+#include "mozilla/Attributes.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/NotNull.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Variant.h"
 #include "mozilla/gfx/2D.h"
 
 #include "imgFrame.h"
 #include "SurfaceCache.h"
 
 namespace mozilla {
 namespace image {
 
 class CachedSurface;
+class DrawableSurface;
 
 /**
  * An interface for objects which can either store a surface or dynamically
  * generate one.
  */
 class ISurfaceProvider
 {
 public:
   // Subclasses may or may not be XPCOM classes, so we just require that they
   // implement AddRef and Release.
   NS_IMETHOD_(MozExternalRefCountType) AddRef() = 0;
   NS_IMETHOD_(MozExternalRefCountType) Release() = 0;
 
-  /// @return a drawable reference to a surface.
-  virtual DrawableFrameRef DrawableRef() = 0;
+  /// @return a (potentially lazily computed) drawable reference to a surface.
+  virtual DrawableSurface Surface();
 
   /// @return true if DrawableRef() will return a completely decoded surface.
   virtual bool IsFinished() const = 0;
 
   /// @return the number of bytes of memory this ISurfaceProvider is expected to
   /// require. Optimizations may result in lower real memory usage. Trivial
   /// overhead is ignored.
   virtual size_t LogicalSizeInBytes() const = 0;
@@ -57,55 +59,139 @@ public:
 
 protected:
   explicit ISurfaceProvider(AvailabilityState aAvailability)
     : mAvailability(aAvailability)
   { }
 
   virtual ~ISurfaceProvider() { }
 
+  /// @return an eagerly computed drawable reference to a surface.
+  virtual DrawableFrameRef DrawableRef() = 0;
+
   /// @return true if this ISurfaceProvider is locked. (@see SetLocked())
   /// Should only be called from SurfaceCache code as it relies on SurfaceCache
   /// for synchronization.
   virtual bool IsLocked() const = 0;
 
   /// If @aLocked is true, hint that this ISurfaceProvider is in use and it
   /// should avoid releasing its resources. Should only be called from
   /// SurfaceCache code as it relies on SurfaceCache for synchronization.
   virtual void SetLocked(bool aLocked) = 0;
 
 private:
   friend class CachedSurface;
+  friend class DrawableSurface;
 
   AvailabilityState mAvailability;
 };
 
+
+/**
+ * A reference to a surface (stored in an imgFrame) that holds the surface in
+ * memory, guaranteeing that it can be drawn. If you have a DrawableSurface
+ * |surf| and |if (surf)| returns true, then calls to |surf->Draw()| and
+ * |surf->GetSurface()| are guaranteed to succeed.
+ *
+ * Note that the surface may be computed lazily, so a DrawableSurface should not
+ * be dereferenced (i.e., operator->() should not be called) until you're
+ * sure that you want to draw it.
+ */
+class MOZ_STACK_CLASS DrawableSurface final
+{
+public:
+  DrawableSurface() : mHaveSurface(false) { }
+
+  explicit DrawableSurface(DrawableFrameRef&& aDrawableRef)
+    : mDrawableRef(Move(aDrawableRef))
+    , mHaveSurface(bool(mDrawableRef))
+  { }
+
+  explicit DrawableSurface(NotNull<ISurfaceProvider*> aProvider)
+    : mProvider(aProvider)
+    , mHaveSurface(true)
+  { }
+
+  DrawableSurface(DrawableSurface&& aOther)
+    : mDrawableRef(Move(aOther.mDrawableRef))
+    , mProvider(Move(aOther.mProvider))
+    , mHaveSurface(aOther.mHaveSurface)
+  {
+    aOther.mHaveSurface = false;
+  }
+
+  DrawableSurface& operator=(DrawableSurface&& aOther)
+  {
+    MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
+    mDrawableRef = Move(aOther.mDrawableRef);
+    mProvider = Move(aOther.mProvider);
+    mHaveSurface = aOther.mHaveSurface;
+    aOther.mHaveSurface = false;
+    return *this;
+  }
+
+  explicit operator bool() const { return mHaveSurface; }
+  imgFrame* operator->() { return DrawableRef().get(); }
+
+private:
+  DrawableSurface(const DrawableSurface& aOther) = delete;
+  DrawableSurface& operator=(const DrawableSurface& aOther) = delete;
+
+  DrawableFrameRef& DrawableRef()
+  {
+    MOZ_ASSERT(mHaveSurface);
+
+    // If we weren't created with a DrawableFrameRef directly, we should've been
+    // created with an ISurfaceProvider which can give us one.
+    if (!mDrawableRef) {
+      MOZ_ASSERT(mProvider);
+      mDrawableRef = mProvider->DrawableRef();
+    }
+
+    MOZ_ASSERT(mDrawableRef);
+    return mDrawableRef;
+  }
+
+  DrawableFrameRef mDrawableRef;
+  RefPtr<ISurfaceProvider> mProvider;
+  bool mHaveSurface;
+};
+
+
+// Surface() is implemented here so that DrawableSurface's definition is visible.
+inline DrawableSurface
+ISurfaceProvider::Surface()
+{
+  return DrawableSurface(DrawableRef());
+}
+
+
 /**
  * An ISurfaceProvider that stores a single surface.
  */
 class SimpleSurfaceProvider final : public ISurfaceProvider
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SimpleSurfaceProvider, override)
 
   explicit SimpleSurfaceProvider(NotNull<imgFrame*> aSurface)
     : ISurfaceProvider(AvailabilityState::StartAvailable())
     , mSurface(aSurface)
   { }
 
-  DrawableFrameRef DrawableRef() override { return mSurface->DrawableRef(); }
   bool IsFinished() const override { return mSurface->IsFinished(); }
 
   size_t LogicalSizeInBytes() const override
   {
     gfx::IntSize size = mSurface->GetSize();
     return size.width * size.height * mSurface->GetBytesPerPixel();
   }
 
 protected:
+  DrawableFrameRef DrawableRef() override { return mSurface->DrawableRef(); }
   bool IsLocked() const override { return bool(mLockRef); }
 
   void SetLocked(bool aLocked) override
   {
     if (aLocked == IsLocked()) {
       return;  // Nothing changed.
     }
 
--- a/image/LookupResult.h
+++ b/image/LookupResult.h
@@ -8,17 +8,17 @@
  * combines a surface with relevant metadata tracked by SurfaceCache.
  */
 
 #ifndef mozilla_image_LookupResult_h
 #define mozilla_image_LookupResult_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/Move.h"
-#include "imgFrame.h"
+#include "ISurfaceProvider.h"
 
 namespace mozilla {
 namespace image {
 
 enum class MatchType : uint8_t
 {
   NOT_FOUND,  // No matching surface and no placeholder.
   PENDING,    // Found a matching placeholder, but no surface.
@@ -39,52 +39,52 @@ public:
     : mMatchType(aMatchType)
   {
     MOZ_ASSERT(mMatchType == MatchType::NOT_FOUND ||
                mMatchType == MatchType::PENDING,
                "Only NOT_FOUND or PENDING make sense with no surface");
   }
 
   LookupResult(LookupResult&& aOther)
-    : mDrawableRef(Move(aOther.mDrawableRef))
+    : mSurface(Move(aOther.mSurface))
     , mMatchType(aOther.mMatchType)
   { }
 
-  LookupResult(DrawableFrameRef&& aDrawableRef, MatchType aMatchType)
-    : mDrawableRef(Move(aDrawableRef))
+  LookupResult(DrawableSurface&& aSurface, MatchType aMatchType)
+    : mSurface(Move(aSurface))
     , mMatchType(aMatchType)
   {
-    MOZ_ASSERT(!mDrawableRef || !(mMatchType == MatchType::NOT_FOUND ||
-                                  mMatchType == MatchType::PENDING),
+    MOZ_ASSERT(!mSurface || !(mMatchType == MatchType::NOT_FOUND ||
+                              mMatchType == MatchType::PENDING),
                "Only NOT_FOUND or PENDING make sense with no surface");
-    MOZ_ASSERT(mDrawableRef || mMatchType == MatchType::NOT_FOUND ||
-                               mMatchType == MatchType::PENDING,
+    MOZ_ASSERT(mSurface || mMatchType == MatchType::NOT_FOUND ||
+                           mMatchType == MatchType::PENDING,
                "NOT_FOUND or PENDING do not make sense with a surface");
   }
 
   LookupResult& operator=(LookupResult&& aOther)
   {
     MOZ_ASSERT(&aOther != this, "Self-move-assignment is not supported");
-    mDrawableRef = Move(aOther.mDrawableRef);
+    mSurface = Move(aOther.mSurface);
     mMatchType = aOther.mMatchType;
     return *this;
   }
 
-  DrawableFrameRef& DrawableRef() { return mDrawableRef; }
-  const DrawableFrameRef& DrawableRef() const { return mDrawableRef; }
+  DrawableSurface& Surface() { return mSurface; }
+  const DrawableSurface& Surface() const { return mSurface; }
 
   /// @return true if this LookupResult contains a surface.
-  explicit operator bool() const { return bool(mDrawableRef); }
+  explicit operator bool() const { return bool(mSurface); }
 
   /// @return what kind of match this is (exact, substitute, etc.)
   MatchType Type() const { return mMatchType; }
 
 private:
   LookupResult(const LookupResult&) = delete;
 
-  DrawableFrameRef mDrawableRef;
+  DrawableSurface mSurface;
   MatchType mMatchType;
 };
 
 } // namespace image
 } // namespace mozilla
 
 #endif // mozilla_image_LookupResult_h
--- a/image/RasterImage.cpp
+++ b/image/RasterImage.cpp
@@ -301,40 +301,40 @@ RasterImage::LookupFrameInternal(uint32_
 
   // We'll return the best match we can find to the requested frame.
   return SurfaceCache::LookupBestMatch(ImageKey(this),
                                        RasterSurfaceKey(aSize,
                                                         surfaceFlags,
                                                         aFrameNum));
 }
 
-DrawableFrameRef
+DrawableSurface
 RasterImage::LookupFrame(uint32_t aFrameNum,
                          const IntSize& aSize,
                          uint32_t aFlags)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // If we're opaque, we don't need to care about premultiplied alpha, because
   // that can only matter for frames with transparency.
   if (IsOpaque()) {
     aFlags &= ~FLAG_DECODE_NO_PREMULTIPLY_ALPHA;
   }
 
   IntSize requestedSize = CanDownscaleDuringDecode(aSize, aFlags)
                         ? aSize : mSize;
   if (requestedSize.IsEmpty()) {
-    return DrawableFrameRef();  // Can't decode to a surface of zero size.
+    return DrawableSurface();  // Can't decode to a surface of zero size.
   }
 
   LookupResult result = LookupFrameInternal(aFrameNum, requestedSize, aFlags);
 
   if (!result && !mHasSize) {
     // We can't request a decode without knowing our intrinsic size. Give up.
-    return DrawableFrameRef();
+    return DrawableSurface();
   }
 
   if (result.Type() == MatchType::NOT_FOUND ||
       result.Type() == MatchType::SUBSTITUTE_BECAUSE_NOT_FOUND ||
       ((aFlags & FLAG_SYNC_DECODE) && !result)) {
     // We don't have a copy of this frame, and there's no decoder working on
     // one. (Or we're sync decoding and the existing decoder hasn't even started
     // yet.) Trigger decoding so it'll be available next time.
@@ -346,43 +346,43 @@ RasterImage::LookupFrame(uint32_t aFrame
     // If we can sync decode, we should already have the frame.
     if (aFlags & FLAG_SYNC_DECODE) {
       result = LookupFrameInternal(aFrameNum, requestedSize, aFlags);
     }
   }
 
   if (!result) {
     // We still weren't able to get a frame. Give up.
-    return DrawableFrameRef();
+    return DrawableSurface();
   }
 
-  if (result.DrawableRef()->GetCompositingFailed()) {
-    return DrawableFrameRef();
+  if (result.Surface()->GetCompositingFailed()) {
+    return DrawableSurface();
   }
 
-  MOZ_ASSERT(!result.DrawableRef()->GetIsPaletted(),
+  MOZ_ASSERT(!result.Surface()->GetIsPaletted(),
              "Should not have a paletted frame");
 
   // Sync decoding guarantees that we got the frame, but if it's owned by an
   // async decoder that's currently running, the contents of the frame may not
   // be available yet. Make sure we get everything.
   if (mHasSourceData && (aFlags & FLAG_SYNC_DECODE)) {
-    result.DrawableRef()->WaitUntilFinished();
+    result.Surface()->WaitUntilFinished();
   }
 
   // If we could have done some decoding in this function we need to check if
   // that decoding encountered an error and hence aborted the surface. We want
   // to avoid calling IsAborted if we weren't passed any sync decode flag because
   // IsAborted acquires the monitor for the imgFrame.
   if (aFlags & (FLAG_SYNC_DECODE | FLAG_SYNC_DECODE_IF_FAST) &&
-    result.DrawableRef()->IsAborted()) {
-    return DrawableFrameRef();
+    result.Surface()->IsAborted()) {
+    return DrawableSurface();
   }
 
-  return Move(result.DrawableRef());
+  return Move(result.Surface());
 }
 
 uint32_t
 RasterImage::GetCurrentFrameIndex() const
 {
   if (mAnimationState) {
     return mAnimationState->GetCurrentAnimationFrameIndex();
   }
@@ -502,30 +502,30 @@ RasterImage::GetFrameInternal(const IntS
 
   if (mError) {
     return MakePair(DrawResult::BAD_IMAGE, RefPtr<SourceSurface>());
   }
 
   // Get the frame. If it's not there, it's probably the caller's fault for
   // not waiting for the data to be loaded from the network or not passing
   // FLAG_SYNC_DECODE
-  DrawableFrameRef frameRef =
+  DrawableSurface surface =
     LookupFrame(GetRequestedFrameIndex(aWhichFrame), aSize, aFlags);
-  if (!frameRef) {
+  if (!surface) {
     // The OS threw this frame away and we couldn't redecode it.
     return MakePair(DrawResult::TEMPORARY_ERROR, RefPtr<SourceSurface>());
   }
 
-  RefPtr<SourceSurface> frameSurf = frameRef->GetSurface();
+  RefPtr<SourceSurface> sourceSurface = surface->GetSurface();
 
-  if (!frameRef->IsFinished()) {
-    return MakePair(DrawResult::INCOMPLETE, Move(frameSurf));
+  if (!surface->IsFinished()) {
+    return MakePair(DrawResult::INCOMPLETE, Move(sourceSurface));
   }
 
-  return MakePair(DrawResult::SUCCESS, Move(frameSurf));
+  return MakePair(DrawResult::SUCCESS, Move(sourceSurface));
 }
 
 Pair<DrawResult, RefPtr<layers::Image>>
 RasterImage::GetCurrentImage(ImageContainer* aContainer, uint32_t aFlags)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aContainer);
 
@@ -1261,41 +1261,41 @@ RasterImage::CanDownscaleDuringDecode(co
   if (!SurfaceCache::CanHold(aSize)) {
     return false;
   }
 
   return true;
 }
 
 DrawResult
-RasterImage::DrawInternal(DrawableFrameRef&& aFrameRef,
+RasterImage::DrawInternal(DrawableSurface&& aSurface,
                           gfxContext* aContext,
                           const IntSize& aSize,
                           const ImageRegion& aRegion,
                           SamplingFilter aSamplingFilter,
                           uint32_t aFlags)
 {
   gfxContextMatrixAutoSaveRestore saveMatrix(aContext);
   ImageRegion region(aRegion);
-  bool frameIsFinished = aFrameRef->IsFinished();
+  bool frameIsFinished = aSurface->IsFinished();
 
   // By now we may have a frame with the requested size. If not, we need to
   // adjust the drawing parameters accordingly.
-  IntSize finalSize = aFrameRef->GetImageSize();
+  IntSize finalSize = aSurface->GetImageSize();
   bool couldRedecodeForBetterFrame = false;
   if (finalSize != aSize) {
     gfx::Size scale(double(aSize.width) / finalSize.width,
                     double(aSize.height) / finalSize.height);
     aContext->Multiply(gfxMatrix::Scaling(scale.width, scale.height));
     region.Scale(1.0 / scale.width, 1.0 / scale.height);
 
     couldRedecodeForBetterFrame = CanDownscaleDuringDecode(aSize, aFlags);
   }
 
-  if (!aFrameRef->Draw(aContext, region, aSamplingFilter, aFlags)) {
+  if (!aSurface->Draw(aContext, region, aSamplingFilter, aFlags)) {
     RecoverFromInvalidFrames(aSize, aFlags);
     return DrawResult::TEMPORARY_ERROR;
   }
   if (!frameIsFinished) {
     return DrawResult::INCOMPLETE;
   }
   if (couldRedecodeForBetterFrame) {
     return DrawResult::WRONG_SIZE;
@@ -1337,30 +1337,30 @@ RasterImage::Draw(gfxContext* aContext,
   }
 
   // If we're not using SamplingFilter::GOOD, we shouldn't high-quality scale or
   // downscale during decode.
   uint32_t flags = aSamplingFilter == SamplingFilter::GOOD
                  ? aFlags
                  : aFlags & ~FLAG_HIGH_QUALITY_SCALING;
 
-  DrawableFrameRef ref =
+  DrawableSurface surface =
     LookupFrame(GetRequestedFrameIndex(aWhichFrame), aSize, flags);
-  if (!ref) {
+  if (!surface) {
     // Getting the frame (above) touches the image and kicks off decoding.
     if (mDrawStartTime.IsNull()) {
       mDrawStartTime = TimeStamp::Now();
     }
     return DrawResult::NOT_READY;
   }
 
   bool shouldRecordTelemetry = !mDrawStartTime.IsNull() &&
-                               ref->IsFinished();
+                               surface->IsFinished();
 
-  auto result = DrawInternal(Move(ref), aContext, aSize,
+  auto result = DrawInternal(Move(surface), aContext, aSize,
                              aRegion, aSamplingFilter, flags);
 
   if (shouldRecordTelemetry) {
       TimeDuration drawLatency = TimeStamp::Now() - mDrawStartTime;
       Telemetry::Accumulate(Telemetry::IMAGE_DECODE_ON_DRAW_LATENCY,
                             int32_t(drawLatency.ToMicroseconds()));
       mDrawStartTime = TimeStamp();
   }
--- a/image/RasterImage.h
+++ b/image/RasterImage.h
@@ -17,23 +17,23 @@
 #ifndef mozilla_image_RasterImage_h
 #define mozilla_image_RasterImage_h
 
 #include "Image.h"
 #include "nsCOMPtr.h"
 #include "imgIContainer.h"
 #include "nsIProperties.h"
 #include "nsTArray.h"
-#include "imgFrame.h"
 #include "LookupResult.h"
 #include "nsThreadUtils.h"
 #include "DecodePool.h"
 #include "DecoderFactory.h"
 #include "FrameAnimator.h"
 #include "ImageMetadata.h"
+#include "ISurfaceProvider.h"
 #include "Orientation.h"
 #include "nsIObserver.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/NotNull.h"
 #include "mozilla/Pair.h"
 #include "mozilla/TimeStamp.h"
@@ -268,34 +268,34 @@ public:
       GetURI()->GetSpec(spec);
     }
     return spec;
   }
 
 private:
   nsresult Init(const char* aMimeType, uint32_t aFlags);
 
-  DrawResult DrawInternal(DrawableFrameRef&& aFrameRef,
+  DrawResult DrawInternal(DrawableSurface&& aSurface,
                           gfxContext* aContext,
                           const nsIntSize& aSize,
                           const ImageRegion& aRegion,
                           gfx::SamplingFilter aSamplingFilter,
                           uint32_t aFlags);
 
   Pair<DrawResult, RefPtr<gfx::SourceSurface>>
     GetFrameInternal(const gfx::IntSize& aSize,
                      uint32_t aWhichFrame,
                      uint32_t aFlags);
 
   LookupResult LookupFrameInternal(uint32_t aFrameNum,
                                    const gfx::IntSize& aSize,
                                    uint32_t aFlags);
-  DrawableFrameRef LookupFrame(uint32_t aFrameNum,
-                               const nsIntSize& aSize,
-                               uint32_t aFlags);
+  DrawableSurface LookupFrame(uint32_t aFrameNum,
+                              const nsIntSize& aSize,
+                              uint32_t aFlags);
   uint32_t GetCurrentFrameIndex() const;
   uint32_t GetRequestedFrameIndex(uint32_t aWhichFrame) const;
 
   Pair<DrawResult, RefPtr<layers::Image>>
     GetCurrentImage(layers::ImageContainer* aContainer, uint32_t aFlags);
 
   void UpdateImageContainer();
 
--- a/image/SurfaceCache.cpp
+++ b/image/SurfaceCache.cpp
@@ -141,24 +141,24 @@ public:
     , mImageKey(aImageKey)
     , mSurfaceKey(aSurfaceKey)
   {
     MOZ_ASSERT(aProvider || mCost == sPlaceholderCost,
                "Old-style placeholders should have trivial cost");
     MOZ_ASSERT(mImageKey, "Must have a valid image key");
   }
 
-  DrawableFrameRef DrawableRef() const
+  DrawableSurface GetDrawableSurface() const
   {
     if (MOZ_UNLIKELY(IsPlaceholder())) {
-      MOZ_ASSERT_UNREACHABLE("Shouldn't call DrawableRef() on a placeholder");
-      return DrawableFrameRef();
+      MOZ_ASSERT_UNREACHABLE("Called GetDrawableSurface() on a placeholder");
+      return DrawableSurface();
     }
 
-    return mProvider->DrawableRef();
+    return mProvider->Surface();
   }
 
   void SetLocked(bool aLocked)
   {
     if (IsPlaceholder()) {
       return;  // Can't lock a placeholder.
     }
 
@@ -194,39 +194,38 @@ public:
     void Add(CachedSurface* aCachedSurface)
     {
       MOZ_ASSERT(aCachedSurface, "Should have a CachedSurface");
 
       SurfaceMemoryCounter counter(aCachedSurface->GetSurfaceKey(),
                                    aCachedSurface->IsLocked());
 
       if (!aCachedSurface->IsPlaceholder()) {
-        DrawableFrameRef surfaceRef = aCachedSurface->DrawableRef();
-        if (surfaceRef) {
-          counter.SubframeSize() = Some(surfaceRef->GetSize());
+        DrawableSurface drawableSurface = aCachedSurface->GetDrawableSurface();
+        if (drawableSurface) {
+          counter.SubframeSize() = Some(drawableSurface->GetSize());
 
           size_t heap = 0, nonHeap = 0;
-          surfaceRef->AddSizeOfExcludingThis(mMallocSizeOf, heap, nonHeap);
+          drawableSurface->AddSizeOfExcludingThis(mMallocSizeOf, heap, nonHeap);
           counter.Values().SetDecodedHeap(heap);
           counter.Values().SetDecodedNonHeap(nonHeap);
         }
       }
 
       mCounters.AppendElement(counter);
     }
 
   private:
     nsTArray<SurfaceMemoryCounter>& mCounters;
     MallocSizeOf                    mMallocSizeOf;
   };
 
 private:
   nsExpirationState  mExpirationState;
   RefPtr<ISurfaceProvider> mProvider;
-  DrawableFrameRef   mDrawableRef;
   const Cost         mCost;
   const ImageKey     mImageKey;
   const SurfaceKey   mSurfaceKey;
 };
 
 static int64_t
 AreaOfIntSize(const IntSize& aSize) {
   return static_cast<int64_t>(aSize.width) * static_cast<int64_t>(aSize.height);
@@ -594,31 +593,31 @@ public:
       // Lookup in the per-image cache missed.
       return LookupResult(MatchType::NOT_FOUND);
     }
 
     if (surface->IsPlaceholder()) {
       return LookupResult(MatchType::PENDING);
     }
 
-    DrawableFrameRef ref = surface->DrawableRef();
-    if (!ref) {
+    DrawableSurface drawableSurface = surface->GetDrawableSurface();
+    if (!drawableSurface) {
       // The surface was released by the operating system. Remove the cache
       // entry as well.
       Remove(surface);
       return LookupResult(MatchType::NOT_FOUND);
     }
 
     if (aMarkUsed) {
       MarkUsed(surface, cache);
     }
 
     MOZ_ASSERT(surface->GetSurfaceKey() == aSurfaceKey,
                "Lookup() not returning an exact match?");
-    return LookupResult(Move(ref), MatchType::EXACT);
+    return LookupResult(Move(drawableSurface), MatchType::EXACT);
   }
 
   LookupResult LookupBestMatch(const ImageKey         aImageKey,
                                const SurfaceKey&      aSurfaceKey)
   {
     RefPtr<ImageSurfaceCache> cache = GetImageCache(aImageKey);
     if (!cache) {
       // No cached surfaces for this image.
@@ -627,27 +626,27 @@ public:
 
     // Repeatedly look up the best match, trying again if the resulting surface
     // has been freed by the operating system, until we can either lock a
     // surface for drawing or there are no matching surfaces left.
     // XXX(seth): This is O(N^2), but N is expected to be very small. If we
     // encounter a performance problem here we can revisit this.
 
     RefPtr<CachedSurface> surface;
-    DrawableFrameRef ref;
+    DrawableSurface drawableSurface;
     MatchType matchType = MatchType::NOT_FOUND;
     while (true) {
       Tie(surface, matchType) = cache->LookupBestMatch(aSurfaceKey);
 
       if (!surface) {
         return LookupResult(matchType);  // Lookup in the per-image cache missed.
       }
 
-      ref = surface->DrawableRef();
-      if (ref) {
+      drawableSurface = surface->GetDrawableSurface();
+      if (drawableSurface) {
         break;
       }
 
       // The surface was released by the operating system. Remove the cache
       // entry as well.
       Remove(surface);
     }
 
@@ -658,17 +657,17 @@ public:
       surface->GetSurfaceKey().SVGContext() == aSurfaceKey.SVGContext() &&
       surface->GetSurfaceKey().AnimationTime() == aSurfaceKey.AnimationTime() &&
       surface->GetSurfaceKey().Flags() == aSurfaceKey.Flags());
 
     if (matchType == MatchType::EXACT) {
       MarkUsed(surface, cache);
     }
 
-    return LookupResult(Move(ref), matchType);
+    return LookupResult(Move(drawableSurface), matchType);
   }
 
   bool CanHold(const Cost aCost) const
   {
     return aCost <= mMaxCost;
   }
 
   size_t MaximumCapacity() const
--- a/image/SurfaceCache.h
+++ b/image/SurfaceCache.h
@@ -207,40 +207,37 @@ struct SurfaceCache
    * Note that this will never happen to ISurfaceProviders associated with a
    * locked image; SurfaceCache tells such ISurfaceProviders to keep a strong
    * references to their data internally.
    *
    * @param aImageKey       Key data identifying which image the cache entry
    *                        belongs to.
    * @param aSurfaceKey     Key data which uniquely identifies the requested
    *                        cache entry.
-   * @return                a LookupResult, which will either contain a
-   *                        DrawableFrameRef to a surface, or an empty
-   *                        DrawableFrameRef if the cache entry was not found.
+   * @return                a LookupResult which will contain a DrawableSurface
+   *                        if the cache entry was found.
    */
   static LookupResult Lookup(const ImageKey    aImageKey,
                              const SurfaceKey& aSurfaceKey);
 
   /**
    * Looks up the best matching cache entry and returns a drawable reference to
    * its associated surface.
    *
    * The result may vary from the requested cache entry only in terms of size.
    *
    * @param aImageKey       Key data identifying which image the cache entry
    *                        belongs to.
    * @param aSurfaceKey     Key data which uniquely identifies the requested
    *                        cache entry.
-   * @return                a LookupResult, which will either contain a
-   *                        DrawableFrameRef to a surface similar to the
-   *                        the one the caller requested, or an empty
-   *                        DrawableFrameRef if no acceptable match was found.
-   *                        Callers can use LookupResult::IsExactMatch() to check
-   *                        whether the returned surface exactly matches
-   *                        @aSurfaceKey.
+   * @return                a LookupResult which will contain a DrawableSurface
+   *                        if a cache entry similar to the one the caller
+   *                        requested could be found. Callers can use
+   *                        LookupResult::IsExactMatch() to check whether the
+   *                        returned surface exactly matches @aSurfaceKey.
    */
   static LookupResult LookupBestMatch(const ImageKey    aImageKey,
                                       const SurfaceKey& aSurfaceKey);
 
   /**
    * Insert an ISurfaceProvider into the cache. If an entry with the same
    * ImageKey and SurfaceKey is already in the cache, Insert returns
    * FAILURE_ALREADY_PRESENT. If a matching placeholder is already present, the
--- a/image/VectorImage.cpp
+++ b/image/VectorImage.cpp
@@ -867,20 +867,20 @@ VectorImage::Draw(gfxContext* aContext,
   LookupResult result =
     SurfaceCache::Lookup(ImageKey(this),
                          VectorSurfaceKey(params.size,
                                           params.svgContext,
                                           params.animationTime));
 
   // Draw.
   if (result) {
-    RefPtr<SourceSurface> surface = result.DrawableRef()->GetSurface();
-    if (surface) {
+    RefPtr<SourceSurface> sourceSurface = result.Surface()->GetSurface();
+    if (sourceSurface) {
       RefPtr<gfxDrawable> svgDrawable =
-        new gfxSurfaceDrawable(surface, result.DrawableRef()->GetSize());
+        new gfxSurfaceDrawable(sourceSurface, result.Surface()->GetSize());
       Show(svgDrawable, params);
       return DrawResult::SUCCESS;
     }
 
     // We lost our surface due to some catastrophic event.
     RecoverFromLossOfSurfaces();
   }