Bug 994081 - [2/3] Convert imgFrame to SourceSurfaces, r=seth
authorMichael Wu <mwu@mozilla.com>
Sat, 19 Apr 2014 21:28:38 -0400
changeset 207547 013456bbf74d5517f53ca1f04206d758ddeae0be
parent 207546 4c16ab7d8eefba4d096788363ae9fdd8f62b7d99
child 207548 79624417d24728cd9b64a4196712530825ff2390
push id494
push userraliiev@mozilla.com
push dateMon, 25 Aug 2014 18:42:16 +0000
treeherdermozilla-release@a3cc3e46b571 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersseth
bugs994081
milestone32.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 994081 - [2/3] Convert imgFrame to SourceSurfaces, r=seth
gfx/thebes/gfxUtils.cpp
gfx/thebes/gfxUtils.h
image/decoders/nsGIFDecoder2.cpp
image/decoders/nsPNGDecoder.cpp
image/decoders/nsPNGDecoder.h
image/src/ClippedImage.cpp
image/src/Decoder.cpp
image/src/Decoder.h
image/src/FrameBlender.cpp
image/src/OrientedImage.cpp
image/src/RasterImage.cpp
image/src/RasterImage.h
image/src/VectorImage.cpp
image/src/imgFrame.cpp
image/src/imgFrame.h
layout/base/nsLayoutUtils.cpp
--- a/gfx/thebes/gfxUtils.cpp
+++ b/gfx/thebes/gfxUtils.cpp
@@ -192,17 +192,17 @@ OptimalFillOperator()
 // EXTEND_PAD won't help us here; we have to create a temporary surface to hold
 // the subimage of pixels we're allowed to sample.
 static already_AddRefed<gfxDrawable>
 CreateSamplingRestrictedDrawable(gfxDrawable* aDrawable,
                                  gfxContext* aContext,
                                  const gfxMatrix& aUserSpaceToImageSpace,
                                  const gfxRect& aSourceRect,
                                  const gfxRect& aSubimage,
-                                 const gfxImageFormat aFormat)
+                                 const SurfaceFormat aFormat)
 {
     PROFILER_LABEL("gfxUtils", "CreateSamplingRestricedDrawable",
       js::ProfileEntry::Category::GRAPHICS);
 
     gfxRect userSpaceClipExtents = aContext->GetClipExtents();
     // This isn't optimal --- if aContext has a rotation then GetClipExtents
     // will have to do a bounding-box computation, and TransformBounds might
     // too, so we could get a better result if we computed image space clip
@@ -228,19 +228,19 @@ CreateSamplingRestrictedDrawable(gfxDraw
     nsRefPtr<gfxDrawable> drawable;
     gfxIntSize size(int32_t(needed.Width()), int32_t(needed.Height()));
 
     nsRefPtr<gfxImageSurface> image = aDrawable->GetAsImageSurface();
     if (image && gfxRect(0, 0, image->GetSize().width, image->GetSize().height).Contains(needed)) {
       nsRefPtr<gfxASurface> temp = image->GetSubimage(needed);
       drawable = new gfxSurfaceDrawable(temp, size, gfxMatrix().Translate(-needed.TopLeft()));
     } else {
-      mozilla::RefPtr<mozilla::gfx::DrawTarget> target =
+      RefPtr<DrawTarget> target =
         gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(ToIntSize(size),
-                                                                     ImageFormatToSurfaceFormat(aFormat));
+                                                                     aFormat);
       if (!target) {
         return nullptr;
       }
 
       nsRefPtr<gfxContext> tmpCtx = new gfxContext(target);
       tmpCtx->SetOperator(OptimalFillOperator());
       aDrawable->Draw(tmpCtx, needed - needed.TopLeft(), true,
                       GraphicsFilter::FILTER_FAST, gfxMatrix().Translate(needed.TopLeft()));
@@ -398,17 +398,17 @@ static GraphicsFilter ReduceResamplingFi
 /* static */ void
 gfxUtils::DrawPixelSnapped(gfxContext*      aContext,
                            gfxDrawable*     aDrawable,
                            const gfxMatrix& aUserSpaceToImageSpace,
                            const gfxRect&   aSubimage,
                            const gfxRect&   aSourceRect,
                            const gfxRect&   aImageRect,
                            const gfxRect&   aFill,
-                           const gfxImageFormat aFormat,
+                           const SurfaceFormat aFormat,
                            GraphicsFilter aFilter,
                            uint32_t         aImageFlags)
 {
     PROFILER_LABEL("gfxUtils", "DrawPixelSnapped",
       js::ProfileEntry::Category::GRAPHICS);
 
     bool doTile = !aImageRect.Contains(aSourceRect) &&
                   !(aImageFlags & imgIContainer::FLAG_CLAMP);
--- a/gfx/thebes/gfxUtils.h
+++ b/gfx/thebes/gfxUtils.h
@@ -60,17 +60,17 @@ public:
      */
     static void DrawPixelSnapped(gfxContext*      aContext,
                                  gfxDrawable*     aDrawable,
                                  const gfxMatrix& aUserSpaceToImageSpace,
                                  const gfxRect&   aSubimage,
                                  const gfxRect&   aSourceRect,
                                  const gfxRect&   aImageRect,
                                  const gfxRect&   aFill,
-                                 const gfxImageFormat aFormat,
+                                 const mozilla::gfx::SurfaceFormat aFormat,
                                  GraphicsFilter aFilter,
                                  uint32_t         aImageFlags = imgIContainer::FLAG_NONE);
 
     /**
      * Clip aContext to the region aRegion.
      */
     static void ClipToRegion(gfxContext* aContext, const nsIntRegion& aRegion);
 
--- a/image/decoders/nsGIFDecoder2.cpp
+++ b/image/decoders/nsGIFDecoder2.cpp
@@ -154,21 +154,21 @@ void nsGIFDecoder2::BeginGIF()
   mGIFOpen = true;
 
   PostSize(mGIFStruct.screen_width, mGIFStruct.screen_height);
 }
 
 //******************************************************************************
 void nsGIFDecoder2::BeginImageFrame(uint16_t aDepth)
 {
-  gfxImageFormat format;
+  gfx::SurfaceFormat format;
   if (mGIFStruct.is_transparent)
-    format = gfxImageFormat::ARGB32;
+    format = gfx::SurfaceFormat::B8G8R8A8;
   else
-    format = gfxImageFormat::RGB24;
+    format = gfx::SurfaceFormat::B8G8R8X8;
 
   MOZ_ASSERT(HasSize());
 
   // Use correct format, RGB for first frame, PAL for following frames
   // and include transparency to allow for optimization of opaque images
   if (mGIFStruct.images_decoded) {
     // Image data is stored with original depth and palette
     NeedNewFrame(mGIFStruct.images_decoded, mGIFStruct.x_offset,
@@ -183,17 +183,17 @@ void nsGIFDecoder2::BeginImageFrame(uint
                                                                 mGIFStruct.width,
                                                                 mGIFStruct.height))) {
     // Regardless of depth of input, image is decoded into 24bit RGB
     NeedNewFrame(mGIFStruct.images_decoded, mGIFStruct.x_offset,
                  mGIFStruct.y_offset, mGIFStruct.width, mGIFStruct.height,
                  format);
   } else {
     // Our preallocated frame matches up, with the possible exception of alpha.
-    if (format == gfxImageFormat::RGB24) {
+    if (format == gfx::SurfaceFormat::B8G8R8X8) {
       GetCurrentFrame()->SetHasNoAlpha();
     }
   }
 
   mCurrentFrame = mGIFStruct.images_decoded;
 }
 
 
--- a/image/decoders/nsPNGDecoder.cpp
+++ b/image/decoders/nsPNGDecoder.cpp
@@ -135,27 +135,27 @@ nsPNGDecoder::~nsPNGDecoder()
     if (mTransform)
       qcms_transform_release(mTransform);
   }
 }
 
 // CreateFrame() is used for both simple and animated images
 void nsPNGDecoder::CreateFrame(png_uint_32 x_offset, png_uint_32 y_offset,
                                int32_t width, int32_t height,
-                               gfxImageFormat format)
+                               gfx::SurfaceFormat format)
 {
   // Our first full frame is automatically created by the image decoding
   // infrastructure. Just use it as long as it matches up.
   MOZ_ASSERT(HasSize());
   if (mNumFrames != 0 ||
       !GetCurrentFrame()->GetRect().IsEqualEdges(nsIntRect(x_offset, y_offset, width, height))) {
     NeedNewFrame(mNumFrames, x_offset, y_offset, width, height, format);
   } else if (mNumFrames == 0) {
     // Our preallocated frame matches up, with the possible exception of alpha.
-    if (format == gfxImageFormat::RGB24) {
+    if (format == gfx::SurfaceFormat::B8G8R8X8) {
       GetCurrentFrame()->SetHasNoAlpha();
     }
   }
 
   mFrameRect.x = x_offset;
   mFrameRect.y = y_offset;
   mFrameRect.width = width;
   mFrameRect.height = height;
@@ -624,19 +624,19 @@ nsPNGDecoder::info_callback(png_structp 
       }
     } else {
       alpha_bits = 8;
     }
   }
 #endif
 
   if (channels == 1 || channels == 3)
-    decoder->format = gfxImageFormat::RGB24;
+    decoder->format = gfx::SurfaceFormat::B8G8R8X8;
   else if (channels == 2 || channels == 4)
-    decoder->format = gfxImageFormat::ARGB32;
+    decoder->format = gfx::SurfaceFormat::B8G8R8A8;
 
 #ifdef PNG_APNG_SUPPORTED
   if (png_get_valid(png_ptr, info_ptr, PNG_INFO_acTL))
     png_set_progressive_frame_fn(png_ptr, nsPNGDecoder::frame_info_callback,
                                  nullptr);
 
   if (png_get_first_frame_is_hidden(png_ptr, info_ptr)) {
     decoder->mFrameIsHidden = true;
@@ -740,17 +740,17 @@ nsPNGDecoder::row_callback(png_structp p
         }
         line = decoder->mCMSLine;
       } else {
         qcms_transform_data(decoder->mTransform, line, line, iwidth);
        }
      }
 
     switch (decoder->format) {
-      case gfxImageFormat::RGB24:
+      case gfx::SurfaceFormat::B8G8R8X8:
       {
         // counter for while() loops below
         uint32_t idx = iwidth;
 
         // copy as bytes until source pointer is 32-bit-aligned
         for (; (NS_PTR_TO_UINT32(line) & 0x3) && idx; --idx) {
           *cptr32++ = gfxPackedPixel(0xFF, line[0], line[1], line[2]);
           line += 3;
@@ -767,17 +767,17 @@ nsPNGDecoder::row_callback(png_structp p
         // copy remaining pixel(s)
         while (idx--) {
           // 32-bit read of final pixel will exceed buffer, so read bytes
           *cptr32++ = gfxPackedPixel(0xFF, line[0], line[1], line[2]);
           line += 3;
         }
       }
       break;
-      case gfxImageFormat::ARGB32:
+      case gfx::SurfaceFormat::B8G8R8A8:
       {
         if (!decoder->mDisablePremultipliedAlpha) {
           for (uint32_t x=width; x>0; --x) {
             *cptr32++ = gfxPackedPixel(line[3], line[0], line[1], line[2]);
             if (line[3] != 0xff)
               rowHasNoAlpha = false;
             line += 4;
           }
--- a/image/decoders/nsPNGDecoder.h
+++ b/image/decoders/nsPNGDecoder.h
@@ -28,17 +28,17 @@ public:
   virtual ~nsPNGDecoder();
 
   virtual void InitInternal();
   virtual void WriteInternal(const char* aBuffer, uint32_t aCount, DecodeStrategy aStrategy);
   virtual Telemetry::ID SpeedHistogram();
 
   void CreateFrame(png_uint_32 x_offset, png_uint_32 y_offset,
                    int32_t width, int32_t height,
-                   gfxImageFormat format);
+                   gfx::SurfaceFormat format);
   void EndImageFrame();
 
   // Check if PNG is valid ICO (32bpp RGBA)
   // http://blogs.msdn.com/b/oldnewthing/archive/2010/10/22/10079192.aspx
   bool IsValidICO() const
   {
     // If there are errors in the call to png_get_IHDR, the error_callback in
     // nsPNGDecoder.cpp is called.  In this error callback we do a longjmp, so
@@ -71,17 +71,17 @@ public:
   png_structp mPNG;
   png_infop mInfo;
   nsIntRect mFrameRect;
   uint8_t *mCMSLine;
   uint8_t *interlacebuf;
   qcms_profile *mInProfile;
   qcms_transform *mTransform;
 
-  gfxImageFormat format;
+  gfx::SurfaceFormat format;
 
   // For size decodes
   uint8_t mSizeBytes[8]; // Space for width and height, both 4 bytes
   uint32_t mHeaderBytesRead;
 
   // whether CMS or premultiplied alpha are forced off
   uint32_t mCMSMode;
 
--- a/image/src/ClippedImage.cpp
+++ b/image/src/ClippedImage.cpp
@@ -250,17 +250,17 @@ ClippedImage::GetFrameInternal(const nsI
       new DrawSingleTileCallback(this, mClip, aViewportSize, aSVGContext, aWhichFrame, aFlags);
     nsRefPtr<gfxDrawable> drawable =
       new gfxCallbackDrawable(drawTileCallback, mClip.Size());
 
     // Actually draw. The callback will end up invoking DrawSingleTile.
     gfxRect imageRect(0, 0, mClip.width, mClip.height);
     gfxUtils::DrawPixelSnapped(ctx, drawable, gfxMatrix(),
                                imageRect, imageRect, imageRect, imageRect,
-                               gfxImageFormat::ARGB32,
+                               SurfaceFormat::B8G8R8A8,
                                GraphicsFilter::FILTER_FAST);
 
     // Cache the resulting surface.
     mCachedSurface = new ClippedImageCachedSurface(target->Snapshot(),
                                                    aViewportSize,
                                                    aSVGContext,
                                                    frameToDraw,
                                                    aFlags);
@@ -335,17 +335,17 @@ ClippedImage::Draw(gfxContext* aContext,
     nsRefPtr<gfxSurfaceDrawable> drawable =
       new gfxSurfaceDrawable(surface, gfxIntSize(mClip.width, mClip.height));
 
     // Draw.
     gfxRect imageRect(0, 0, mClip.width, mClip.height);
     gfxRect subimage(aSubimage.x, aSubimage.y, aSubimage.width, aSubimage.height);
     gfxUtils::DrawPixelSnapped(aContext, drawable, aUserSpaceToImageSpace,
                                subimage, sourceRect, imageRect, aFill,
-                               gfxImageFormat::ARGB32, aFilter);
+                               SurfaceFormat::B8G8R8A8, aFilter);
 
     return NS_OK;
   }
 
   // Determine the appropriate subimage for the inner image.
   nsIntRect innerSubimage(aSubimage);
   innerSubimage.MoveBy(mClip.x, mClip.y);
   innerSubimage.Intersect(mClip);
--- a/image/src/Decoder.cpp
+++ b/image/src/Decoder.cpp
@@ -198,18 +198,16 @@ Decoder::FinishSharedDecoder()
 }
 
 nsresult
 Decoder::AllocateFrame()
 {
   MOZ_ASSERT(mNeedsNewFrame);
   MOZ_ASSERT(NS_IsMainThread());
 
-  MarkFrameDirty();
-
   nsresult rv;
   imgFrame* frame = nullptr;
   if (mNewFrameData.mPaletteDepth) {
     rv = mImage.EnsureFrame(mNewFrameData.mFrameNum, mNewFrameData.mOffsetX,
                             mNewFrameData.mOffsetY, mNewFrameData.mWidth,
                             mNewFrameData.mHeight, mNewFrameData.mFormat,
                             mNewFrameData.mPaletteDepth,
                             &mImageData, &mImageDataLength,
@@ -416,33 +414,23 @@ Decoder::PostDecoderError(nsresult aFail
   // XXXbholley - we should report the image URI here, but imgContainer
   // needs to know its URI first
   NS_WARNING("Image decoding error - This is probably a bug!");
 }
 
 void
 Decoder::NeedNewFrame(uint32_t framenum, uint32_t x_offset, uint32_t y_offset,
                       uint32_t width, uint32_t height,
-                      gfxImageFormat format,
+                      gfx::SurfaceFormat format,
                       uint8_t palette_depth /* = 0 */)
 {
   // Decoders should never call NeedNewFrame without yielding back to Write().
   MOZ_ASSERT(!mNeedsNewFrame);
 
   // We don't want images going back in time or skipping frames.
   MOZ_ASSERT(framenum == mFrameCount || framenum == (mFrameCount - 1));
 
   mNewFrameData = NewFrameData(framenum, x_offset, y_offset, width, height, format, palette_depth);
   mNeedsNewFrame = true;
 }
 
-void
-Decoder::MarkFrameDirty()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  if (mCurrentFrame) {
-    mCurrentFrame->ApplyDirtToSurfaces();
-  }
-}
-
 } // namespace image
 } // namespace mozilla
--- a/image/src/Decoder.h
+++ b/image/src/Decoder.h
@@ -146,29 +146,25 @@ public:
   // is created as an ARGB frame with no offset and with size width * height.
   // If decoders need something different, they must ask for it.
   // This is called by decoders when they need a new frame. These decoders
   // must then save the data they have been sent but not yet processed and
   // return from WriteInternal. When the new frame is created, WriteInternal
   // will be called again with nullptr and 0 as arguments.
   void NeedNewFrame(uint32_t frameNum, uint32_t x_offset, uint32_t y_offset,
                     uint32_t width, uint32_t height,
-                    gfxImageFormat format,
+                    gfx::SurfaceFormat format,
                     uint8_t palette_depth = 0);
 
   virtual bool NeedsNewFrame() const { return mNeedsNewFrame; }
 
   // Try to allocate a frame as described in mNewFrameData and return the
   // status code from that attempt. Clears mNewFrameData.
   virtual nsresult AllocateFrame();
 
-  // Called when a chunk of decoding has been done and the frame needs to be
-  // marked as dirty. Must be called only on the main thread.
-  void MarkFrameDirty();
-
   imgFrame* GetCurrentFrame() const { return mCurrentFrame; }
 
 protected:
 
   /*
    * Internal hooks. Decoder implementations may override these and
    * only these methods.
    */
@@ -245,31 +241,31 @@ private:
 
   struct NewFrameData
   {
     NewFrameData()
     {}
 
     NewFrameData(uint32_t num, uint32_t offsetx, uint32_t offsety,
                  uint32_t width, uint32_t height,
-                 gfxImageFormat format, uint8_t paletteDepth)
+                 gfx::SurfaceFormat format, uint8_t paletteDepth)
       : mFrameNum(num)
       , mOffsetX(offsetx)
       , mOffsetY(offsety)
       , mWidth(width)
       , mHeight(height)
       , mFormat(format)
       , mPaletteDepth(paletteDepth)
     {}
     uint32_t mFrameNum;
     uint32_t mOffsetX;
     uint32_t mOffsetY;
     uint32_t mWidth;
     uint32_t mHeight;
-    gfxImageFormat mFormat;
+    gfx::SurfaceFormat mFormat;
     uint8_t mPaletteDepth;
   };
   NewFrameData mNewFrameData;
   bool mNeedsNewFrame;
   bool mInitialized;
   bool mSizeDecode;
   bool mInFrame;
   bool mIsAnimated;
--- a/image/src/FrameBlender.cpp
+++ b/image/src/FrameBlender.cpp
@@ -256,17 +256,17 @@ FrameBlender::DoBlend(nsIntRect* aDirtyR
   }
 
   bool needToBlankComposite = false;
 
   // Create the Compositing Frame
   if (!mAnim->compositingFrame) {
     mAnim->compositingFrame.SetFrame(new imgFrame());
     nsresult rv = mAnim->compositingFrame->Init(0, 0, mSize.width, mSize.height,
-                                                gfxImageFormat::ARGB32);
+                                                gfx::SurfaceFormat::B8G8R8A8);
     if (NS_FAILED(rv)) {
       mAnim->compositingFrame.SetFrame(nullptr);
       return false;
     }
     mAnim->compositingFrame.LockAndGetData();
     needToBlankComposite = true;
   } else if (int32_t(aNextFrameIndex) != mAnim->lastCompositedFrameIndex+1) {
 
@@ -386,17 +386,17 @@ FrameBlender::DoBlend(nsIntRect* aDirtyR
   if ((nextFrameDisposalMethod == FrameBlender::kDisposeRestorePrevious) &&
       (prevFrameDisposalMethod != FrameBlender::kDisposeRestorePrevious)) {
     // We are storing the whole image.
     // It would be better if we just stored the area that nextFrame is going to
     // overwrite.
     if (!mAnim->compositingPrevFrame) {
       mAnim->compositingPrevFrame.SetFrame(new imgFrame());
       nsresult rv = mAnim->compositingPrevFrame->Init(0, 0, mSize.width, mSize.height,
-                                                      gfxImageFormat::ARGB32);
+                                                      gfx::SurfaceFormat::B8G8R8A8);
       if (NS_FAILED(rv)) {
         mAnim->compositingPrevFrame.SetFrame(nullptr);
         return false;
       }
 
       mAnim->compositingPrevFrame.LockAndGetData();
     }
 
--- a/image/src/OrientedImage.cpp
+++ b/image/src/OrientedImage.cpp
@@ -95,23 +95,20 @@ OrientedImage::GetFrame(uint32_t aWhichF
   NS_ENSURE_SUCCESS(rv, nullptr);
   if (mOrientation.SwapsWidthAndHeight()) {
     swap(width, height);
   }
   NS_ENSURE_SUCCESS(rv, nullptr);
 
   // Determine an appropriate format for the surface.
   gfx::SurfaceFormat surfaceFormat;
-  gfxImageFormat imageFormat;
   if (InnerImage()->FrameIsOpaque(aWhichFrame)) {
     surfaceFormat = gfx::SurfaceFormat::B8G8R8X8;
-    imageFormat = gfxImageFormat::ARGB32;
   } else {
     surfaceFormat = gfx::SurfaceFormat::B8G8R8A8;
-    imageFormat = gfxImageFormat::ARGB32;
   }
 
   // Create a surface to draw into.
   mozilla::RefPtr<DrawTarget> target =
     gfxPlatform::GetPlatform()->
       CreateOffscreenContentDrawTarget(IntSize(width, height), surfaceFormat);
   if (!target) {
     NS_ERROR("Could not create a DrawTarget");
@@ -126,17 +123,17 @@ OrientedImage::GetFrame(uint32_t aWhichF
   nsRefPtr<gfxDrawable> drawable =
     new gfxSurfaceDrawable(innerSurface, gfxIntSize(width, height));
 
   // Draw.
   nsRefPtr<gfxContext> ctx = new gfxContext(target);
   gfxRect imageRect(0, 0, width, height);
   gfxUtils::DrawPixelSnapped(ctx, drawable, OrientationMatrix(nsIntSize(width, height)),
                              imageRect, imageRect, imageRect, imageRect,
-                             imageFormat, GraphicsFilter::FILTER_FAST);
+                             surfaceFormat, GraphicsFilter::FILTER_FAST);
   
   return target->Snapshot();
 }
 
 NS_IMETHODIMP
 OrientedImage::GetImageContainer(LayerManager* aManager, ImageContainer** _retval)
 {
   // XXX(seth): We currently don't have a way of orienting the result of
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -207,43 +207,37 @@ public:
     nsRefPtr<RasterImage> image = weakImage.get();
     if (!image) {
       return false;
     }
 
     bool success = false;
     if (!dstLocked) {
       bool srcLocked = NS_SUCCEEDED(srcFrame->LockImageData());
+      srcSurface = srcFrame->GetSurface();
+
       dstLocked = NS_SUCCEEDED(dstFrame->LockImageData());
-
-      nsRefPtr<gfxASurface> dstASurf;
-      nsRefPtr<gfxASurface> srcASurf;
-      success = srcLocked && NS_SUCCEEDED(srcFrame->GetSurface(getter_AddRefs(srcASurf)));
-      success = success && dstLocked && NS_SUCCEEDED(dstFrame->GetSurface(getter_AddRefs(dstASurf)));
-
-      success = success && srcLocked && dstLocked && srcASurf && dstASurf;
+      dstSurface = dstFrame->GetSurface();
+
+      success = srcLocked && dstLocked && srcSurface && dstSurface;
 
       if (success) {
-        srcSurface = srcASurf->GetAsImageSurface();
-        dstSurface = dstASurf->GetAsImageSurface();
-        srcData = srcSurface->Data();
-        dstData = dstSurface->Data();
-        srcStride = srcSurface->Stride();
-        dstStride = dstSurface->Stride();
-        srcFormat = mozilla::gfx::ImageFormatToSurfaceFormat(srcFrame->GetFormat());
+        srcData = srcFrame->GetImageData();
+        dstData = dstFrame->GetImageData();
+        srcStride = srcFrame->GetImageBytesPerRow();
+        dstStride = dstFrame->GetImageBytesPerRow();
+        srcFormat = srcFrame->GetFormat();
       }
 
-      // We have references to the Thebes surfaces, so we don't need to leave
+      // We have references to the surfaces, so we don't need to leave
       // the source frame (that we don't own) locked. We'll unlock the
       // destination frame in ReleaseSurfaces(), below.
       if (srcLocked) {
         success = NS_SUCCEEDED(srcFrame->UnlockImageData()) && success;
       }
-
-      success = success && srcSurface && dstSurface;
     }
 
     return success;
   }
 
   // This can only be called on the main thread.
   bool ReleaseSurfaces()
   {
@@ -267,28 +261,28 @@ public:
       dstSurface = nullptr;
     }
     return success;
   }
 
   // These values may only be touched on the main thread.
   WeakPtr<RasterImage> weakImage;
   nsAutoPtr<imgFrame> dstFrame;
-  nsRefPtr<gfxImageSurface> srcSurface;
-  nsRefPtr<gfxImageSurface> dstSurface;
+  RefPtr<SourceSurface> srcSurface;
+  RefPtr<SourceSurface> dstSurface;
 
   // Below are the values that may be touched on the scaling thread.
   gfxSize scale;
   uint8_t* srcData;
   uint8_t* dstData;
   nsIntRect srcRect;
   gfxIntSize dstSize;
   uint32_t srcStride;
   uint32_t dstStride;
-  mozilla::gfx::SurfaceFormat srcFormat;
+  SurfaceFormat srcFormat;
   bool dstLocked;
   bool done;
   // This boolean is accessed from both threads simultaneously without locking.
   // That's safe because stopping a ScaleRequest is strictly an optimization;
   // if we're not cache-coherent, at worst we'll do extra work.
   bool stopped;
 };
 
@@ -330,17 +324,17 @@ public:
   ScaleRunner(RasterImage* aImage, const gfxSize& aScale, imgFrame* aSrcFrame)
   {
     nsAutoPtr<ScaleRequest> request(new ScaleRequest(aImage, aScale, aSrcFrame));
 
     // Destination is unconditionally ARGB32 because that's what the scaler
     // outputs.
     request->dstFrame = new imgFrame();
     nsresult rv = request->dstFrame->Init(0, 0, request->dstSize.width, request->dstSize.height,
-                                          gfxImageFormat::ARGB32);
+                                          SurfaceFormat::B8G8R8A8);
 
     if (NS_FAILED(rv) || !request->GetSurfaces(aSrcFrame)) {
       return;
     }
 
     aImage->ScalingStart(request);
 
     mScaleRequest = request;
@@ -696,20 +690,16 @@ RasterImage::GetDrawableImgFrame(uint32_
     frame = GetImgFrame(framenum);
   }
 
   // We will return a paletted frame if it's not marked as compositing failed
   // so we can catch crashes for reasons we haven't investigated.
   if (frame && frame->GetCompositingFailed())
     return nullptr;
 
-  if (frame) {
-    frame->ApplyDirtToSurfaces();
-  }
-
   return frame;
 }
 
 uint32_t
 RasterImage::GetCurrentImgFrameIndex() const
 {
   if (mAnim)
     return mAnim->GetCurrentAnimationFrameIndex();
@@ -826,73 +816,85 @@ RasterImage::GetFirstFrameDelay()
 
   bool animated = false;
   if (NS_FAILED(GetAnimated(&animated)) || !animated)
     return -1;
 
   return mFrameBlender.GetTimeoutForFrame(0);
 }
 
-nsresult
+TemporaryRef<SourceSurface>
 RasterImage::CopyFrame(uint32_t aWhichFrame,
-                       uint32_t aFlags,
-                       gfxImageSurface **_retval)
+                       uint32_t aFlags)
 {
   if (aWhichFrame > FRAME_MAX_VALUE)
-    return NS_ERROR_INVALID_ARG;
+    return nullptr;
 
   if (mError)
-    return NS_ERROR_FAILURE;
+    return nullptr;
 
   // Disallowed in the API
   if (mInDecoder && (aFlags & imgIContainer::FLAG_SYNC_DECODE))
-    return NS_ERROR_FAILURE;
+    return nullptr;
 
   nsresult rv;
 
   if (!ApplyDecodeFlags(aFlags, aWhichFrame))
-    return NS_ERROR_NOT_AVAILABLE;
+    return nullptr;
 
   // If requested, synchronously flush any data we have lying around to the decoder
   if (aFlags & FLAG_SYNC_DECODE) {
     rv = SyncDecode();
-    CONTAINER_ENSURE_SUCCESS(rv);
+    CONTAINER_ENSURE_TRUE(NS_SUCCEEDED(rv), nullptr);
   }
 
-  NS_ENSURE_ARG_POINTER(_retval);
-
   // 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
   uint32_t frameIndex = (aWhichFrame == FRAME_FIRST) ?
                         0 : GetCurrentImgFrameIndex();
   imgFrame *frame = GetDrawableImgFrame(frameIndex);
   if (!frame) {
-    *_retval = nullptr;
-    return NS_ERROR_FAILURE;
+    return nullptr;
   }
 
-  nsRefPtr<gfxPattern> pattern;
-  frame->GetPattern(getter_AddRefs(pattern));
-  nsIntRect intframerect = frame->GetRect();
-  gfxRect framerect(intframerect.x, intframerect.y, intframerect.width, intframerect.height);
-
   // Create a 32-bit image surface of our size, but draw using the frame's
   // rect, implicitly padding the frame out to the image's size.
-  nsRefPtr<gfxImageSurface> imgsurface = new gfxImageSurface(gfxIntSize(mSize.width, mSize.height),
-                                                             gfxImageFormat::ARGB32);
-  gfxContext ctx(imgsurface);
-  ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
-  ctx.Rectangle(framerect);
-  ctx.Translate(framerect.TopLeft());
-  ctx.SetPattern(pattern);
-  ctx.Fill();
-
-  imgsurface.forget(_retval);
-  return NS_OK;
+
+  IntSize size(mSize.width, mSize.height);
+  RefPtr<DataSourceSurface> surf =
+    Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8);
+
+  DataSourceSurface::MappedSurface mapping;
+  DebugOnly<bool> success =
+    surf->Map(DataSourceSurface::MapType::WRITE, &mapping);
+  NS_ASSERTION(success, "Failed to map surface");
+  RefPtr<DrawTarget> target =
+    Factory::CreateDrawTargetForData(BackendType::CAIRO,
+                                     mapping.mData,
+                                     size,
+                                     mapping.mStride,
+                                     SurfaceFormat::B8G8R8A8);
+
+  nsIntRect intframerect = frame->GetRect();
+  Rect rect(intframerect.x, intframerect.y,
+            intframerect.width, intframerect.height);
+  if (frame->IsSinglePixel()) {
+    target->FillRect(rect, ColorPattern(frame->SinglePixelColor()),
+                     DrawOptions(1.0f, CompositionOp::OP_SOURCE));
+  } else {
+    RefPtr<SourceSurface> srcsurf = frame->GetSurface();
+    Rect srcrect(0, 0, intframerect.width, intframerect.height);
+    target->DrawSurface(srcsurf, srcrect, rect);
+  }
+
+  target->Flush();
+  surf->Unmap();
+
+  return surf;
 }
 
 //******************************************************************************
 /* [noscript] SourceSurface getFrame(in uint32_t aWhichFrame,
  *                                   in uint32_t aFlags); */
 NS_IMETHODIMP_(TemporaryRef<SourceSurface>)
 RasterImage::GetFrame(uint32_t aWhichFrame,
                       uint32_t aFlags)
@@ -923,25 +925,25 @@ RasterImage::GetFrame(uint32_t aWhichFra
   // FLAG_SYNC_DECODE
   uint32_t frameIndex = (aWhichFrame == FRAME_FIRST) ?
                           0 : GetCurrentImgFrameIndex();
   imgFrame *frame = GetDrawableImgFrame(frameIndex);
   if (!frame) {
     return nullptr;
   }
 
-  nsRefPtr<gfxASurface> framesurf;
+  RefPtr<SourceSurface> framesurf;
 
   // If this frame covers the entire image, we can just reuse its existing
   // surface.
   nsIntRect framerect = frame->GetRect();
   if (framerect.x == 0 && framerect.y == 0 &&
       framerect.width == mSize.width &&
       framerect.height == mSize.height) {
-    frame->GetSurface(getter_AddRefs(framesurf));
+    framesurf = frame->GetSurface();
     if (!framesurf && !frame->IsSinglePixel()) {
       // No reason to be optimized away here - the OS threw out the data
       if (!(aFlags & FLAG_SYNC_DECODE))
         return nullptr;
 
       // Unconditionally call ForceDiscard() here because GetSurface can only
       // return null when we can forcibly discard and redecode. There are two
       // other cases where GetSurface() can return null - when it is a single
@@ -952,37 +954,20 @@ RasterImage::GetFrame(uint32_t aWhichFra
       ForceDiscard();
       return GetFrame(aWhichFrame, aFlags);
     }
   }
 
   // The image doesn't have a surface because it's been optimized away. Create
   // one.
   if (!framesurf) {
-    nsRefPtr<gfxImageSurface> imgsurf;
-    CopyFrame(aWhichFrame, aFlags, getter_AddRefs(imgsurf));
-    framesurf = imgsurf;
+    framesurf = CopyFrame(aWhichFrame, aFlags);
   }
 
-  RefPtr<SourceSurface> result;
-
-  // As far as Moz2D is concerned, SourceSurface contains premultiplied alpha.
-  // If we're abusing it to contain non-premultiplied alpha then we want to
-  // avoid having Moz2D do any conversions on it (like copy to another
-  // surface). Hence why we try to wrap framesurf's data here for
-  // FLAG_DECODE_NO_PREMULTIPLY_ALPHA.
-  if ((aFlags & FLAG_WANT_DATA_SURFACE) != 0 ||
-      (aFlags & FLAG_DECODE_NO_PREMULTIPLY_ALPHA) != 0) {
-    result = gfxPlatform::GetPlatform()->GetWrappedDataSourceSurface(framesurf);
-  }
-  if (!result) {
-    result = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(nullptr,
-                                                                    framesurf);
-  }
-  return result.forget();
+  return framesurf;
 }
 
 already_AddRefed<layers::Image>
 RasterImage::GetCurrentImage()
 {
   if (!mDecoded) {
     // We can't call StartDecoding because that can synchronously notify
     // which can cause DOM modification
@@ -1177,17 +1162,17 @@ RasterImage::InternalAddFrameHelper(uint
 
   return NS_OK;
 }
 
 nsresult
 RasterImage::InternalAddFrame(uint32_t framenum,
                               int32_t aX, int32_t aY,
                               int32_t aWidth, int32_t aHeight,
-                              gfxImageFormat aFormat,
+                              SurfaceFormat aFormat,
                               uint8_t aPaletteDepth,
                               uint8_t **imageData,
                               uint32_t *imageLength,
                               uint32_t **paletteData,
                               uint32_t *paletteLength,
                               imgFrame** aRetFrame)
 {
   // We assume that we're in the middle of decoding because we unlock the
@@ -1314,17 +1299,17 @@ RasterImage::SetSize(int32_t aWidth, int
   mFrameBlender.SetSize(mSize);
 
   return NS_OK;
 }
 
 nsresult
 RasterImage::EnsureFrame(uint32_t aFrameNum, int32_t aX, int32_t aY,
                          int32_t aWidth, int32_t aHeight,
-                         gfxImageFormat aFormat,
+                         SurfaceFormat aFormat,
                          uint8_t aPaletteDepth,
                          uint8_t **imageData, uint32_t *imageLength,
                          uint32_t **paletteData, uint32_t *paletteLength,
                          imgFrame** aRetFrame)
 {
   if (mError)
     return NS_ERROR_FAILURE;
 
@@ -1389,17 +1374,17 @@ RasterImage::EnsureFrame(uint32_t aFrame
   return InternalAddFrameHelper(aFrameNum, newFrame.forget(), imageData,
                                 imageLength, paletteData, paletteLength,
                                 aRetFrame);
 }
 
 nsresult
 RasterImage::EnsureFrame(uint32_t aFramenum, int32_t aX, int32_t aY,
                          int32_t aWidth, int32_t aHeight,
-                         gfxImageFormat aFormat,
+                         SurfaceFormat aFormat,
                          uint8_t** imageData, uint32_t* imageLength,
                          imgFrame** aFrame)
 {
   return EnsureFrame(aFramenum, aX, aY, aWidth, aHeight, aFormat,
                      /* aPaletteDepth = */ 0, imageData, imageLength,
                      /* aPaletteData = */ nullptr,
                      /* aPaletteLength = */ nullptr,
                      aFrame);
@@ -2107,17 +2092,17 @@ RasterImage::InitDecoder(bool aDoSizeDec
   mDecoder->SetObserver(mDecodeRequest->mStatusTracker->GetDecoderObserver());
   mDecoder->SetSizeDecode(aDoSizeDecode);
   mDecoder->SetDecodeFlags(mFrameDecodeFlags);
   if (!aDoSizeDecode) {
     // We already have the size; tell the decoder so it can preallocate a
     // frame.  By default, we create an ARGB frame with no offset. If decoders
     // need a different type, they need to ask for it themselves.
     mDecoder->NeedNewFrame(0, 0, 0, mSize.width, mSize.height,
-                           gfxImageFormat::ARGB32);
+                           SurfaceFormat::B8G8R8A8);
     mDecoder->AllocateFrame();
   }
   mDecoder->Init();
   CONTAINER_ENSURE_SUCCESS(mDecoder->GetDecoderError());
 
   if (!aDoSizeDecode) {
     Telemetry::GetHistogramById(Telemetry::IMAGE_DECODE_COUNT)->Subtract(mDecodeCount);
     mDecodeCount++;
@@ -2566,17 +2551,16 @@ RasterImage::ScalingDone(ScaleRequest* r
   MOZ_ASSERT(status == SCALE_DONE || status == SCALE_INVALID);
   MOZ_ASSERT(request);
 
   if (status == SCALE_DONE) {
     MOZ_ASSERT(request->done);
 
     imgFrame *scaledFrame = request->dstFrame.forget();
     scaledFrame->ImageUpdated(scaledFrame->GetRect());
-    scaledFrame->ApplyDirtToSurfaces();
 
     if (mStatusTracker) {
       mStatusTracker->FrameChanged(&request->srcRect);
     }
 
     mScaleResult.status = SCALE_DONE;
     mScaleResult.frame = scaledFrame;
     mScaleResult.scale = request->scale;
@@ -2604,31 +2588,31 @@ RasterImage::DrawWithPreDownscaleIfNeede
 {
   imgFrame *frame = aFrame;
   nsIntRect framerect = frame->GetRect();
   gfxMatrix userSpaceToImageSpace = aUserSpaceToImageSpace;
   gfxMatrix imageSpaceToUserSpace = aUserSpaceToImageSpace;
   imageSpaceToUserSpace.Invert();
   gfxSize scale = imageSpaceToUserSpace.ScaleFactors(true);
   nsIntRect subimage = aSubimage;
-  nsRefPtr<gfxASurface> surf;
+  RefPtr<SourceSurface> surf;
 
   if (CanScale(aFilter, scale, aFlags) && !frame->IsSinglePixel()) {
     // If scale factor is still the same that we scaled for and
     // ScaleWorker isn't still working, then we can use pre-downscaled frame.
     // If scale factor has changed, order new request.
     // FIXME: Current implementation doesn't support pre-downscale
     // mechanism for multiple sizes from same src, since we cache
     // pre-downscaled frame only for the latest requested scale.
     // The solution is to cache more than one scaled image frame
     // for each RasterImage.
     bool needScaleReq;
     if (mScaleResult.status == SCALE_DONE && mScaleResult.scale == scale) {
       // Grab and hold the surface to make sure the OS didn't destroy it
-      mScaleResult.frame->GetSurface(getter_AddRefs(surf));
+      surf = mScaleResult.frame->GetSurface();
       needScaleReq = !surf;
       if (surf) {
         frame = mScaleResult.frame;
         userSpaceToImageSpace.Multiply(gfxMatrix().Scale(scale.width,
                                                          scale.height));
 
         // Since we're switching to a scaled image, we need to transform the
         // area of the subimage to draw accordingly, since imgFrame::Draw()
@@ -3093,18 +3077,16 @@ RasterImage::FinishedSomeDecoding(eShutd
   // destroy it by destroying the decoder.
   nsRefPtr<RasterImage> image(this);
 
   bool done = false;
   bool wasSize = false;
   nsresult rv = NS_OK;
 
   if (image->mDecoder) {
-    image->mDecoder->MarkFrameDirty();
-
     if (request && request->mChunkCount && !image->mDecoder->IsSizeDecode()) {
       Telemetry::Accumulate(Telemetry::IMAGE_DECODE_CHUNKS, request->mChunkCount);
     }
 
     if (!image->mHasSize && image->mDecoder->HasSize()) {
       image->mDecoder->SetSizeOnImage();
     }
 
--- a/image/src/RasterImage.h
+++ b/image/src/RasterImage.h
@@ -201,31 +201,31 @@ public:
   /**
    * Ensures that a given frame number exists with the given parameters, and
    * returns pointers to the data storage for that frame.
    * It is not possible to create sparse frame arrays; you can only append
    * frames to the current frame array.
    */
   nsresult EnsureFrame(uint32_t aFramenum, int32_t aX, int32_t aY,
                        int32_t aWidth, int32_t aHeight,
-                       gfxImageFormat aFormat,
+                       gfx::SurfaceFormat aFormat,
                        uint8_t aPaletteDepth,
                        uint8_t** imageData,
                        uint32_t* imageLength,
                        uint32_t** paletteData,
                        uint32_t* paletteLength,
                        imgFrame** aFrame);
 
   /**
    * A shorthand for EnsureFrame, above, with aPaletteDepth = 0 and paletteData
    * and paletteLength set to null.
    */
   nsresult EnsureFrame(uint32_t aFramenum, int32_t aX, int32_t aY,
                        int32_t aWidth, int32_t aHeight,
-                       gfxImageFormat aFormat,
+                       gfx::SurfaceFormat aFormat,
                        uint8_t** imageData,
                        uint32_t* imageLength,
                        imgFrame** aFrame);
 
   /* notification that the entire image has been decoded */
   nsresult DecodingComplete();
 
   /**
@@ -552,19 +552,18 @@ private:
   bool DrawWithPreDownscaleIfNeeded(imgFrame *aFrame,
                                     gfxContext *aContext,
                                     GraphicsFilter aFilter,
                                     const gfxMatrix &aUserSpaceToImageSpace,
                                     const gfxRect &aFill,
                                     const nsIntRect &aSubimage,
                                     uint32_t aFlags);
 
-  nsresult CopyFrame(uint32_t aWhichFrame,
-                     uint32_t aFlags,
-                     gfxImageSurface **_retval);
+  TemporaryRef<gfx::SourceSurface> CopyFrame(uint32_t aWhichFrame,
+                                             uint32_t aFlags);
 
   /**
    * Deletes and nulls out the frame in mFrames[framenum].
    *
    * Does not change the size of mFrames.
    *
    * @param framenum The index of the frame to be deleted.
    *                 Must lie in [0, mFrames.Length() )
@@ -582,17 +581,17 @@ private:
 
   void EnsureAnimExists();
 
   nsresult InternalAddFrameHelper(uint32_t framenum, imgFrame *frame,
                                   uint8_t **imageData, uint32_t *imageLength,
                                   uint32_t **paletteData, uint32_t *paletteLength,
                                   imgFrame** aRetFrame);
   nsresult InternalAddFrame(uint32_t framenum, int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight,
-                            gfxImageFormat aFormat, uint8_t aPaletteDepth,
+                            gfx::SurfaceFormat aFormat, uint8_t aPaletteDepth,
                             uint8_t **imageData, uint32_t *imageLength,
                             uint32_t **paletteData, uint32_t *paletteLength,
                             imgFrame** aRetFrame);
 
   nsresult DoImageDataComplete();
 
   bool ApplyDecodeFlags(uint32_t aNewFlags, uint32_t aWhichFrame);
 
--- a/image/src/VectorImage.cpp
+++ b/image/src/VectorImage.cpp
@@ -908,17 +908,17 @@ VectorImage::CreateDrawableAndShow(const
   nsRefPtr<gfxContext> ctx = new gfxContext(target);
 
   // Actually draw. (We use FILTER_NEAREST since we never scale here.)
   gfxUtils::DrawPixelSnapped(ctx, svgDrawable, gfxMatrix(),
                              ThebesIntRect(aParams.imageRect),
                              ThebesIntRect(aParams.imageRect),
                              ThebesIntRect(aParams.imageRect),
                              ThebesIntRect(aParams.imageRect),
-                             gfxImageFormat::ARGB32,
+                             SurfaceFormat::B8G8R8A8,
                              GraphicsFilter::FILTER_NEAREST, aParams.flags);
 
   // Attempt to cache the resulting surface.
   SurfaceCache::Insert(target,
                        ImageKey(this),
                        SurfaceKey(aParams.imageRect.Size(), aParams.scale,
                                   aParams.svgContext, aParams.animationTime,
                                   aParams.flags));
@@ -935,17 +935,17 @@ VectorImage::CreateDrawableAndShow(const
 void
 VectorImage::Show(gfxDrawable* aDrawable, const SVGDrawingParameters& aParams)
 {
   MOZ_ASSERT(aDrawable, "Should have a gfxDrawable by now");
   gfxUtils::DrawPixelSnapped(aParams.context, aDrawable,
                              aParams.userSpaceToImageSpace,
                              aParams.subimage, aParams.sourceRect,
                              ThebesIntRect(aParams.imageRect), aParams.fill,
-                             gfxImageFormat::ARGB32,
+                             SurfaceFormat::B8G8R8A8,
                              aParams.filter, aParams.flags);
 
   MOZ_ASSERT(mRenderingObserver, "Should have a rendering observer by now");
   mRenderingObserver->ResumeHonoringInvalidations();
 }
 
 //******************************************************************************
 /* void requestDecode() */
--- a/image/src/imgFrame.cpp
+++ b/image/src/imgFrame.cpp
@@ -17,64 +17,55 @@
 static bool gDisableOptimize = false;
 
 #include "cairo.h"
 #include "GeckoProfiler.h"
 #include "mozilla/Likely.h"
 #include "mozilla/MemoryReporting.h"
 #include "nsMargin.h"
 #include "mozilla/CheckedInt.h"
-
-#if defined(XP_WIN)
-
-#include "gfxWindowsPlatform.h"
-
-/* Whether to use the windows surface; only for desktop win32 */
-#define USE_WIN_SURFACE 1
-
-#endif
+#include "mozilla/gfx/Tools.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::image;
 
-static cairo_user_data_key_t kVolatileBuffer;
+static UserDataKey kVolatileBuffer;
 
 static void
 VolatileBufferRelease(void *vbuf)
 {
   delete static_cast<VolatileBufferPtr<unsigned char>*>(vbuf);
 }
 
-gfxImageSurface *
-LockedImageSurface::CreateSurface(VolatileBuffer *vbuf,
-                                  const gfxIntSize& size,
-                                  gfxImageFormat format)
+static TemporaryRef<DataSourceSurface>
+CreateLockedSurface(VolatileBuffer *vbuf,
+                    const IntSize& size,
+                    SurfaceFormat format)
 {
   VolatileBufferPtr<unsigned char> *vbufptr =
     new VolatileBufferPtr<unsigned char>(vbuf);
   MOZ_ASSERT(!vbufptr->WasBufferPurged(), "Expected image data!");
 
-  long stride = gfxImageSurface::ComputeStride(size, format);
-  gfxImageSurface *img = new gfxImageSurface(*vbufptr, size, stride, format);
-  if (!img || img->CairoStatus()) {
-    delete img;
+  int32_t stride = size.width * BytesPerPixel(format);
+  RefPtr<DataSourceSurface> surf =
+    Factory::CreateWrappingDataSourceSurface(*vbufptr, stride, size, format);
+  if (!surf) {
     delete vbufptr;
     return nullptr;
   }
 
-  img->SetData(&kVolatileBuffer, vbufptr, VolatileBufferRelease);
-  return img;
+  surf->AddUserData(&kVolatileBuffer, vbufptr, VolatileBufferRelease);
+  return surf;
 }
 
-TemporaryRef<VolatileBuffer>
-LockedImageSurface::AllocateBuffer(const gfxIntSize& size,
-                                   gfxImageFormat format)
+static TemporaryRef<VolatileBuffer>
+AllocateBufferForImage(const IntSize& size, SurfaceFormat format)
 {
-  long stride = gfxImageSurface::ComputeStride(size, format);
+  int32_t stride = size.width * BytesPerPixel(format);
   RefPtr<VolatileBuffer> buf = new VolatileBuffer();
   if (buf->Init(stride * size.height,
                 1 << gfxAlphaRecovery::GoodAlignmentLog2()))
     return buf;
 
   return nullptr;
 }
 
@@ -104,61 +95,29 @@ static bool AllowedImageSize(int32_t aWi
   if (MOZ_UNLIKELY(aHeight > SHRT_MAX)) {
     NS_WARNING("image too big");
     return false;
   }
 #endif
   return true;
 }
 
-// Returns whether we should, at this time, use image surfaces instead of
-// optimized platform-specific surfaces.
-static bool ShouldUseImageSurfaces()
-{
-#if defined(USE_WIN_SURFACE)
-  static const DWORD kGDIObjectsHighWaterMark = 7000;
-
-  if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
-      gfxWindowsPlatform::RENDER_DIRECT2D) {
-    return true;
-  }
-
-  // at 7000 GDI objects, stop allocating normal images to make sure
-  // we never hit the 10k hard limit.
-  // GetCurrentProcess() just returns (HANDLE)-1, it's inlined afaik
-  DWORD count = GetGuiResources(GetCurrentProcess(), GR_GDIOBJECTS);
-  if (count == 0 ||
-      count > kGDIObjectsHighWaterMark)
-  {
-    // either something's broken (count == 0),
-    // or we hit our high water mark; disable
-    // image allocations for a bit.
-    return true;
-  }
-#endif
-
-  return false;
-}
-
 imgFrame::imgFrame() :
   mDecoded(0, 0, 0, 0),
-  mDirtyMutex("imgFrame::mDirty"),
+  mDecodedMutex("imgFrame::mDecoded"),
   mPalettedImageData(nullptr),
-  mSinglePixelColor(0),
   mTimeout(100),
   mDisposalMethod(0), /* imgIContainer::kDisposeNotSpecified */
   mLockCount(0),
   mBlendMethod(1), /* imgIContainer::kBlendOver */
   mSinglePixel(false),
-  mFormatChanged(false),
   mCompositingFailed(false),
   mNonPremult(false),
   mDiscardable(false),
-  mInformedDiscardTracker(false),
-  mDirty(false)
+  mInformedDiscardTracker(false)
 {
   static bool hasCheckedOptimize = false;
   if (!hasCheckedOptimize) {
     if (PR_GetEnv("MOZ_DISABLE_IMAGE_OPTIMIZE")) {
       gDisableOptimize = true;
     }
     hasCheckedOptimize = true;
   }
@@ -170,17 +129,17 @@ imgFrame::~imgFrame()
   mPalettedImageData = nullptr;
 
   if (mInformedDiscardTracker) {
     DiscardTracker::InformDeallocation(4 * mSize.height * mSize.width);
   }
 }
 
 nsresult imgFrame::Init(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight,
-                        gfxImageFormat aFormat, uint8_t aPaletteDepth /* = 0 */)
+                        SurfaceFormat aFormat, uint8_t aPaletteDepth /* = 0 */)
 {
   // assert for properties that should be verified by decoders, warn for properties related to bad content
   if (!AllowedImageSize(aWidth, aHeight)) {
     NS_WARNING("Should have legal image size");
     return NS_ERROR_FAILURE;
   }
 
   mOffset.MoveTo(aX, aY);
@@ -203,65 +162,32 @@ nsresult imgFrame::Init(int32_t aX, int3
       NS_WARNING("moz_malloc for paletted image data should succeed");
     NS_ENSURE_TRUE(mPalettedImageData, NS_ERROR_OUT_OF_MEMORY);
   } else {
     // Inform the discard tracker that we are going to allocate some memory.
     if (!DiscardTracker::TryAllocation(4 * mSize.width * mSize.height)) {
       NS_WARNING("Exceed the hard limit of decode image size");
       return NS_ERROR_OUT_OF_MEMORY;
     }
-    // For Windows, we must create the device surface first (if we're
-    // going to) so that the image surface can wrap it.  Can't be done
-    // the other way around.
-#ifdef USE_WIN_SURFACE
-    if (!ShouldUseImageSurfaces()) {
-      mWinSurface = new gfxWindowsSurface(gfxIntSize(mSize.width, mSize.height), mFormat);
-      if (mWinSurface && mWinSurface->CairoStatus() == 0) {
-        // no error
-        mImageSurface = mWinSurface->GetAsImageSurface();
-      } else {
-        mWinSurface = nullptr;
-      }
-    }
-#endif
-
-    // For other platforms, space for the image surface is first allocated in
-    // a volatile buffer and then wrapped by a LockedImageSurface.
-    // This branch is also used on Windows if we're not using device surfaces
-    // or if we couldn't create one.
     if (!mImageSurface) {
-      mVBuf = LockedImageSurface::AllocateBuffer(mSize, mFormat);
+      mVBuf = AllocateBufferForImage(mSize, mFormat);
       if (!mVBuf) {
         return NS_ERROR_OUT_OF_MEMORY;
       }
-      mImageSurface = LockedImageSurface::CreateSurface(mVBuf, mSize, mFormat);
+      mImageSurface = CreateLockedSurface(mVBuf, mSize, mFormat);
     }
 
-    if (!mImageSurface || mImageSurface->CairoStatus()) {
-      mImageSurface = nullptr;
-      // guess
-      if (!mImageSurface) {
-        NS_WARNING("Allocation of gfxImageSurface should succeed");
-      } else if (!mImageSurface->CairoStatus()) {
-        NS_WARNING("gfxImageSurface should have good CairoStatus");
-      }
-
+    if (!mImageSurface) {
+      NS_WARNING("Failed to create VolatileDataSourceSurface");
       // Image surface allocation is failed, need to return
       // the booked buffer size.
       DiscardTracker::InformDeallocation(4 * mSize.width * mSize.height);
       return NS_ERROR_OUT_OF_MEMORY;
     }
-
     mInformedDiscardTracker = true;
-
-#ifdef XP_MACOSX
-    if (!ShouldUseImageSurfaces()) {
-      mQuartzSurface = new gfxQuartzImageSurface(mImageSurface);
-    }
-#endif
   }
 
   return NS_OK;
 }
 
 nsresult imgFrame::Optimize()
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -276,193 +202,157 @@ nsresult imgFrame::Optimize()
   // Cairo doesn't support non-premult single-colors.
   if (mNonPremult)
     return NS_OK;
 
   /* Figure out if the entire image is a constant color */
 
   // this should always be true
   if (mImageSurface->Stride() == mSize.width * 4) {
-    uint32_t *imgData = (uint32_t*) mImageSurface->Data();
+    uint32_t *imgData = (uint32_t*) ((uint8_t *)mVBufPtr);
     uint32_t firstPixel = * (uint32_t*) imgData;
     uint32_t pixelCount = mSize.width * mSize.height + 1;
 
     while (--pixelCount && *imgData++ == firstPixel)
       ;
 
     if (pixelCount == 0) {
       // all pixels were the same
-      if (mFormat == gfxImageFormat::ARGB32 ||
-          mFormat == gfxImageFormat::RGB24)
-      {
-        // Should already be premult if desired.
-        gfxRGBA::PackedColorType inputType = gfxRGBA::PACKED_XRGB;
-        if (mFormat == gfxImageFormat::ARGB32)
-          inputType = gfxRGBA::PACKED_ARGB_PREMULTIPLIED;
-
-        mSinglePixelColor = gfxRGBA(firstPixel, inputType);
-
+      if (mFormat == SurfaceFormat::B8G8R8A8 ||
+          mFormat == SurfaceFormat::B8G8R8X8) {
         mSinglePixel = true;
+        mSinglePixelColor.a = ((firstPixel >> 24) & 0xFF) * (1.0f / 255.0f);
+        mSinglePixelColor.r = ((firstPixel >> 16) & 0xFF) * (1.0f / 255.0f);
+        mSinglePixelColor.g = ((firstPixel >>  8) & 0xFF) * (1.0f / 255.0f);
+        mSinglePixelColor.b = ((firstPixel >>  0) & 0xFF) * (1.0f / 255.0f);
+        mSinglePixelColor.r /= mSinglePixelColor.a;
+        mSinglePixelColor.g /= mSinglePixelColor.a;
+        mSinglePixelColor.b /= mSinglePixelColor.a;
 
         // blow away the older surfaces (if they exist), to release their memory
         mVBuf = nullptr;
+        mVBufPtr = nullptr;
         mImageSurface = nullptr;
         mOptSurface = nullptr;
-#ifdef USE_WIN_SURFACE
-        mWinSurface = nullptr;
-#endif
-#ifdef XP_MACOSX
-        mQuartzSurface = nullptr;
-#endif
-        mDrawSurface = nullptr;
 
         // We just dumped most of our allocated memory, so tell the discard
         // tracker that we're not using any at all.
         if (mInformedDiscardTracker) {
           DiscardTracker::InformDeallocation(4 * mSize.width * mSize.height);
           mInformedDiscardTracker = false;
         }
 
         return NS_OK;
       }
     }
 
     // if it's not RGB24/ARGB32, don't optimize, but we never hit this at the moment
   }
 
-  // if we're being forced to use image surfaces due to
-  // resource constraints, don't try to optimize beyond same-pixel.
-  if (ShouldUseImageSurfaces())
-    return NS_OK;
-
-  mOptSurface = nullptr;
+#ifdef ANDROID
+  SurfaceFormat optFormat =
+    gfxPlatform::GetPlatform()->Optimal2DFormatForContent(gfxContentType::COLOR);
 
-#ifdef USE_WIN_SURFACE
-  if (mWinSurface) {
-    if (!mFormatChanged) {
-      // just use the DIB if the format has not changed
-      mOptSurface = mWinSurface;
-    }
-  }
-#endif
-
-#ifdef XP_MACOSX
-  if (mQuartzSurface) {
-    mQuartzSurface->Flush();
-  }
-#endif
-
-#ifdef ANDROID
-  gfxImageFormat optFormat =
-    gfxPlatform::GetPlatform()->
-      OptimalFormatForContent(gfxASurface::ContentFromFormat(mFormat));
-
-  if (optFormat == gfxImageFormat::RGB16_565) {
+  if (!GetHasAlpha() && optFormat == SurfaceFormat::R5G6B5) {
     RefPtr<VolatileBuffer> buf =
-      LockedImageSurface::AllocateBuffer(mSize, optFormat);
+      AllocateBufferForImage(mSize, optFormat);
     if (!buf)
       return NS_OK;
 
-    nsRefPtr<gfxImageSurface> surf =
-      LockedImageSurface::CreateSurface(buf, mSize, optFormat);
+    RefPtr<DataSourceSurface> surf =
+      CreateLockedSurface(buf, mSize, optFormat);
+    if (!surf)
+      return NS_ERROR_OUT_OF_MEMORY;
 
-    gfxContext ctx(surf);
-    ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
-    ctx.SetSource(mImageSurface);
-    ctx.Paint();
+    DataSourceSurface::MappedSurface mapping;
+    DebugOnly<bool> success =
+      surf->Map(DataSourceSurface::MapType::WRITE, &mapping);
+    NS_ASSERTION(success, "Failed to map surface");
+    RefPtr<DrawTarget> target =
+      Factory::CreateDrawTargetForData(BackendType::CAIRO,
+                                       mapping.mData,
+                                       mSize,
+                                       mapping.mStride,
+                                       optFormat);
+
+    Rect rect(0, 0, mSize.width, mSize.height);
+    target->DrawSurface(mImageSurface, rect, rect);
+    target->Flush();
+    surf->Unmap();
 
     mImageSurface = surf;
     mVBuf = buf;
     mFormat = optFormat;
-    mDrawSurface = nullptr;
   }
 #else
-  if (mOptSurface == nullptr)
-    mOptSurface = gfxPlatform::GetPlatform()->OptimizeImage(mImageSurface, mFormat);
+  mOptSurface = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget()->OptimizeSourceSurface(mImageSurface);
+  if (mOptSurface == mImageSurface)
+    mOptSurface = nullptr;
 #endif
 
   if (mOptSurface) {
     mVBuf = nullptr;
+    mVBufPtr = nullptr;
     mImageSurface = nullptr;
-#ifdef USE_WIN_SURFACE
-    mWinSurface = nullptr;
-#endif
-#ifdef XP_MACOSX
-    mQuartzSurface = nullptr;
-#endif
-    mDrawSurface = nullptr;
   }
 
   return NS_OK;
 }
 
-static void
-DoSingleColorFastPath(gfxContext*    aContext,
-                      const gfxRGBA& aSinglePixelColor,
-                      const gfxRect& aFill)
-{
-  // if a == 0, it's a noop
-  if (aSinglePixelColor.a == 0.0)
-    return;
-
-  gfxContext::GraphicsOperator op = aContext->CurrentOperator();
-  if (op == gfxContext::OPERATOR_OVER && aSinglePixelColor.a == 1.0) {
-    aContext->SetOperator(gfxContext::OPERATOR_SOURCE);
-  }
-
-  aContext->SetDeviceColor(aSinglePixelColor);
-  aContext->NewPath();
-  aContext->Rectangle(aFill);
-  aContext->Fill();
-  aContext->SetOperator(op);
-  aContext->SetDeviceColor(gfxRGBA(0,0,0,0));
-}
-
 imgFrame::SurfaceWithFormat
 imgFrame::SurfaceForDrawing(bool               aDoPadding,
                             bool               aDoPartialDecode,
                             bool               aDoTile,
                             const nsIntMargin& aPadding,
                             gfxMatrix&         aUserSpaceToImageSpace,
                             gfxRect&           aFill,
                             gfxRect&           aSubimage,
                             gfxRect&           aSourceRect,
                             gfxRect&           aImageRect,
-                            gfxASurface*       aSurface)
+                            SourceSurface*     aSurface)
 {
   IntSize size(int32_t(aImageRect.Width()), int32_t(aImageRect.Height()));
   if (!aDoPadding && !aDoPartialDecode) {
     NS_ASSERTION(!mSinglePixel, "This should already have been handled");
     return SurfaceWithFormat(new gfxSurfaceDrawable(aSurface, ThebesIntSize(size)), mFormat);
   }
 
   gfxRect available = gfxRect(mDecoded.x, mDecoded.y, mDecoded.width, mDecoded.height);
 
   if (aDoTile || mSinglePixel) {
     // Create a temporary surface.
     // Give this surface an alpha channel because there are
     // transparent pixels in the padding or undecoded area
-    gfxImageFormat format = gfxImageFormat::ARGB32;
-    nsRefPtr<gfxASurface> surface =
-      gfxPlatform::GetPlatform()->CreateOffscreenSurface(size, gfxImageSurface::ContentFromFormat(format));
-    if (!surface || surface->CairoStatus())
+    RefPtr<DrawTarget> target =
+      gfxPlatform::GetPlatform()->
+        CreateOffscreenContentDrawTarget(size, SurfaceFormat::B8G8R8A8);
+    if (!target)
       return SurfaceWithFormat();
 
+    Rect fillRect(aFill.x, aFill.y, aFill.width, aFill.height);
     // Fill 'available' with whatever we've got
-    gfxContext tmpCtx(surface);
-    tmpCtx.SetOperator(gfxContext::OPERATOR_SOURCE);
     if (mSinglePixel) {
-      tmpCtx.SetDeviceColor(mSinglePixelColor);
+      target->FillRect(fillRect, ColorPattern(mSinglePixelColor),
+                       DrawOptions(1.0f, CompositionOp::OP_SOURCE));
     } else {
-      tmpCtx.SetSource(aSurface, gfxPoint(aPadding.left, aPadding.top));
+      gfxMatrix imageSpaceToUserSpace = aUserSpaceToImageSpace;
+      imageSpaceToUserSpace.Invert();
+      SurfacePattern pattern(aSurface,
+                             ExtendMode::REPEAT,
+                             Matrix(imageSpaceToUserSpace.xx,
+                                    imageSpaceToUserSpace.xy,
+                                    imageSpaceToUserSpace.yx,
+                                    imageSpaceToUserSpace.yy,
+                                    imageSpaceToUserSpace.x0,
+                                    imageSpaceToUserSpace.y0));
+      target->FillRect(fillRect, pattern);
     }
-    tmpCtx.Rectangle(available);
-    tmpCtx.Fill();
 
-    return SurfaceWithFormat(new gfxSurfaceDrawable(surface, ThebesIntSize(size)), format);
+    RefPtr<SourceSurface> newsurf = target->Snapshot();
+    return SurfaceWithFormat(new gfxSurfaceDrawable(newsurf, ThebesIntSize(size)), target->GetFormat());
   }
 
   // Not tiling, and we have a surface, so we can account for
   // padding and/or a partial decode just by twiddling parameters.
   // First, update our user-space fill rect.
   aSourceRect = aSourceRect.Intersect(available);
   gfxMatrix imageSpaceToUserSpace = aUserSpaceToImageSpace;
   imageSpaceToUserSpace.Invert();
@@ -488,53 +378,42 @@ bool imgFrame::Draw(gfxContext *aContext
 
   NS_ASSERTION(!aFill.IsEmpty(), "zero dest size --- fix caller");
   NS_ASSERTION(!aSubimage.IsEmpty(), "zero source size --- fix caller");
   NS_ASSERTION(!mPalettedImageData, "Directly drawing a paletted image!");
 
   bool doPadding = aPadding != nsIntMargin(0,0,0,0);
   bool doPartialDecode = !ImageComplete();
 
+  RefPtr<DrawTarget> dt = aContext->GetDrawTarget();
+
   if (mSinglePixel && !doPadding && !doPartialDecode) {
-    DoSingleColorFastPath(aContext, mSinglePixelColor, aFill);
+    if (mSinglePixelColor.a == 0.0) {
+      return true;
+    }
+
+    Rect target(aFill.x, aFill.y, aFill.width, aFill.height);
+    dt->FillRect(target, ColorPattern(mSinglePixelColor),
+                 DrawOptions(1.0f, CompositionOpForOp(aContext->CurrentOperator())));
     return true;
   }
 
   gfxMatrix userSpaceToImageSpace = aUserSpaceToImageSpace;
   gfxRect sourceRect = userSpaceToImageSpace.TransformBounds(aFill);
   gfxRect imageRect(0, 0, mSize.width + aPadding.LeftRight(),
                     mSize.height + aPadding.TopBottom());
   gfxRect subimage(aSubimage.x, aSubimage.y, aSubimage.width, aSubimage.height);
   gfxRect fill = aFill;
 
   NS_ASSERTION(!sourceRect.Intersect(subimage).IsEmpty(),
                "We must be allowed to sample *some* source pixels!");
 
-  nsRefPtr<gfxASurface> surf = CachedThebesSurface();
-  VolatileBufferPtr<unsigned char> ref(mVBuf);
-  if (!mSinglePixel && !surf) {
-    if (ref.WasBufferPurged()) {
-      return false;
-    }
-
-    surf = mDrawSurface;
-    if (!surf) {
-      long stride = gfxImageSurface::ComputeStride(mSize, mFormat);
-      nsRefPtr<gfxImageSurface> imgSurf =
-        new gfxImageSurface(ref, mSize, stride, mFormat);
-#if defined(XP_MACOSX)
-      surf = mDrawSurface = new gfxQuartzImageSurface(imgSurf);
-#else
-      surf = mDrawSurface = imgSurf;
-#endif
-    }
-    if (!surf || surf->CairoStatus()) {
-      mDrawSurface = nullptr;
-      return true;
-    }
+  RefPtr<SourceSurface> surf = GetSurface();
+  if (!surf) {
+    return false;
   }
 
   bool doTile = !imageRect.Contains(sourceRect) &&
                 !(aImageFlags & imgIContainer::FLAG_CLAMP);
   SurfaceWithFormat surfaceResult =
     SurfaceForDrawing(doPadding, doPartialDecode, doTile, aPadding,
                       userSpaceToImageSpace, fill, subimage, sourceRect,
                       imageRect, surf);
@@ -546,79 +425,66 @@ bool imgFrame::Draw(gfxContext *aContext
                                surfaceResult.mFormat, aFilter, aImageFlags);
   }
   return true;
 }
 
 // This can be called from any thread, but not simultaneously.
 nsresult imgFrame::ImageUpdated(const nsIntRect &aUpdateRect)
 {
-  MutexAutoLock lock(mDirtyMutex);
+  MutexAutoLock lock(mDecodedMutex);
 
   mDecoded.UnionRect(mDecoded, aUpdateRect);
 
   // clamp to bounds, in case someone sends a bogus updateRect (I'm looking at
   // you, gif decoder)
-  nsIntRect boundsRect(mOffset, mSize);
+  nsIntRect boundsRect(mOffset, nsIntSize(mSize.width, mSize.height));
   mDecoded.IntersectRect(mDecoded, boundsRect);
 
-  mDirty = true;
-
   return NS_OK;
 }
 
-bool imgFrame::GetIsDirty() const
+nsIntRect imgFrame::GetRect() const
 {
-  MutexAutoLock lock(mDirtyMutex);
-  return mDirty;
+  return nsIntRect(mOffset, nsIntSize(mSize.width, mSize.height));
 }
 
-nsIntRect imgFrame::GetRect() const
-{
-  return nsIntRect(mOffset, mSize);
-}
-
-gfxImageFormat imgFrame::GetFormat() const
+SurfaceFormat imgFrame::GetFormat() const
 {
   return mFormat;
 }
 
 bool imgFrame::GetNeedsBackground() const
 {
   // We need a background painted if we have alpha or we're incomplete.
-  return (mFormat == gfxImageFormat::ARGB32 || !ImageComplete());
+  return (mFormat == SurfaceFormat::B8G8R8A8 || !ImageComplete());
 }
 
 uint32_t imgFrame::GetImageBytesPerRow() const
 {
-  if (mImageSurface)
-    return mImageSurface->Stride();
-
   if (mVBuf)
-    return gfxImageSurface::ComputeStride(mSize, mFormat);
+    return mSize.width * BytesPerPixel(mFormat);
 
   if (mPaletteDepth)
     return mSize.width;
 
-  NS_ERROR("GetImageBytesPerRow called with mImageSurface == null, mVBuf == null and mPaletteDepth == 0");
-
   return 0;
 }
 
 uint32_t imgFrame::GetImageDataLength() const
 {
   return GetImageBytesPerRow() * mSize.height;
 }
 
 void imgFrame::GetImageData(uint8_t **aData, uint32_t *length) const
 {
   NS_ABORT_IF_FALSE(mLockCount != 0, "Can't GetImageData unless frame is locked");
 
   if (mImageSurface)
-    *aData = mImageSurface->Data();
+    *aData = mVBufPtr;
   else if (mPalettedImageData)
     *aData = mPalettedImageData + PaletteDataLength();
   else
     *aData = nullptr;
 
   *length = GetImageDataLength();
 }
 
@@ -632,17 +498,17 @@ uint8_t* imgFrame::GetImageData() const
 
 bool imgFrame::GetIsPaletted() const
 {
   return mPalettedImageData != nullptr;
 }
 
 bool imgFrame::GetHasAlpha() const
 {
-  return mFormat == gfxImageFormat::ARGB32;
+  return mFormat == SurfaceFormat::B8G8R8A8;
 }
 
 void imgFrame::GetPaletteData(uint32_t **aPalette, uint32_t *length) const
 {
   NS_ABORT_IF_FALSE(mLockCount != 0, "Can't GetPaletteData unless frame is locked");
 
   if (!mPalettedImageData) {
     *aPalette = nullptr;
@@ -682,76 +548,69 @@ nsresult imgFrame::LockImageData()
     return NS_OK;
 
   if (!mImageSurface) {
     if (mVBuf) {
       VolatileBufferPtr<uint8_t> ref(mVBuf);
       if (ref.WasBufferPurged())
         return NS_ERROR_FAILURE;
 
-      mImageSurface = LockedImageSurface::CreateSurface(mVBuf, mSize, mFormat);
-      if (!mImageSurface || mImageSurface->CairoStatus())
+      mImageSurface = CreateLockedSurface(mVBuf, mSize, mFormat);
+      if (!mImageSurface)
         return NS_ERROR_OUT_OF_MEMORY;
     }
-    if (mOptSurface || mSinglePixel || mFormat == gfxImageFormat::RGB16_565) {
-      gfxImageFormat format = mFormat;
-      if (mFormat == gfxImageFormat::RGB16_565)
-        format = gfxImageFormat::ARGB32;
+    if (mOptSurface || mSinglePixel || mFormat == SurfaceFormat::R5G6B5) {
+      SurfaceFormat format = mFormat;
+      if (mFormat == SurfaceFormat::R5G6B5)
+        format = SurfaceFormat::B8G8R8A8;
 
       // Recover the pixels
       RefPtr<VolatileBuffer> buf =
-        LockedImageSurface::AllocateBuffer(mSize, format);
+        AllocateBufferForImage(mSize, format);
       if (!buf) {
         return NS_ERROR_OUT_OF_MEMORY;
       }
 
-      RefPtr<gfxImageSurface> surf =
-        LockedImageSurface::CreateSurface(buf, mSize, mFormat);
-      if (!surf || surf->CairoStatus())
+      RefPtr<DataSourceSurface> surf =
+        CreateLockedSurface(buf, mSize, format);
+      if (!surf)
         return NS_ERROR_OUT_OF_MEMORY;
 
-      gfxContext context(surf);
-      context.SetOperator(gfxContext::OPERATOR_SOURCE);
+      DataSourceSurface::MappedSurface mapping;
+      DebugOnly<bool> success =
+        surf->Map(DataSourceSurface::MapType::WRITE, &mapping);
+      NS_ASSERTION(success, "Failed to map surface");
+      RefPtr<DrawTarget> target =
+        Factory::CreateDrawTargetForData(BackendType::CAIRO,
+                                         mapping.mData,
+                                         mSize,
+                                         mapping.mStride,
+                                         format);
+
+      Rect rect(0, 0, mSize.width, mSize.height);
       if (mSinglePixel)
-        context.SetDeviceColor(mSinglePixelColor);
-      else if (mFormat == gfxImageFormat::RGB16_565)
-        context.SetSource(mImageSurface);
+        target->FillRect(rect, ColorPattern(mSinglePixelColor),
+                         DrawOptions(1.0f, CompositionOp::OP_SOURCE));
+      else if (mFormat == SurfaceFormat::R5G6B5)
+        target->DrawSurface(mImageSurface, rect, rect);
       else
-        context.SetSource(mOptSurface);
-      context.Paint();
+        target->DrawSurface(mOptSurface, rect, rect,
+                            DrawSurfaceOptions(),
+                            DrawOptions(1.0f, CompositionOp::OP_SOURCE));
+      target->Flush();
+      surf->Unmap();
 
       mFormat = format;
       mVBuf = buf;
       mImageSurface = surf;
       mOptSurface = nullptr;
-#ifdef USE_WIN_SURFACE
-      mWinSurface = nullptr;
-#endif
-#ifdef XP_MACOSX
-      mQuartzSurface = nullptr;
-#endif
     }
   }
 
-  // We might write to the bits in this image surface, so we need to make the
-  // surface ready for that.
-  if (mImageSurface)
-    mImageSurface->Flush();
-
-#ifdef USE_WIN_SURFACE
-  if (mWinSurface)
-    mWinSurface->Flush();
-#endif
-
-#ifdef XP_MACOSX
-  if (!mQuartzSurface && !ShouldUseImageSurfaces()) {
-    mQuartzSurface = new gfxQuartzImageSurface(mImageSurface);
-  }
-#endif
-
+  mVBufPtr = mVBuf;
   return NS_OK;
 }
 
 nsresult imgFrame::UnlockImageData()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   NS_ABORT_IF_FALSE(mLockCount != 0, "Unlocking an unlocked image!");
@@ -770,98 +629,56 @@ nsresult imgFrame::UnlockImageData()
   if (mLockCount != 0) {
     return NS_OK;
   }
 
   // Paletted images don't have surfaces, so there's nothing to do.
   if (mPalettedImageData)
     return NS_OK;
 
-  // FIXME: Bug 795737
-  // If this image has been drawn since we were locked, it has had snapshots
-  // added, and we need to remove them before calling MarkDirty.
-  if (mImageSurface)
-    mImageSurface->Flush();
-
-#ifdef USE_WIN_SURFACE
-  if (mWinSurface)
-    mWinSurface->Flush();
-#endif
-
-  // Assume we've been written to.
-  if (mImageSurface)
-    mImageSurface->MarkDirty();
-
-#ifdef USE_WIN_SURFACE
-  if (mWinSurface)
-    mWinSurface->MarkDirty();
-#endif
-
-#ifdef XP_MACOSX
-  // The quartz image surface (ab)uses the flush method to get the
-  // cairo_image_surface data into a CGImage, so we have to call Flush() here.
-  if (mQuartzSurface)
-    mQuartzSurface->Flush();
-#endif
-
+  mVBufPtr = nullptr;
   if (mVBuf && mDiscardable) {
     mImageSurface = nullptr;
-#ifdef XP_MACOSX
-    mQuartzSurface = nullptr;
-#endif
   }
 
   return NS_OK;
 }
 
-void imgFrame::ApplyDirtToSurfaces()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  MutexAutoLock lock(mDirtyMutex);
-  if (mDirty) {
-    // FIXME: Bug 795737
-    // If this image has been drawn since we were locked, it has had snapshots
-    // added, and we need to remove them before calling MarkDirty.
-    if (mImageSurface)
-      mImageSurface->Flush();
-
-#ifdef USE_WIN_SURFACE
-    if (mWinSurface)
-      mWinSurface->Flush();
-#endif
-
-    if (mImageSurface)
-      mImageSurface->MarkDirty();
-
-#ifdef USE_WIN_SURFACE
-    if (mWinSurface)
-      mWinSurface->MarkDirty();
-#endif
-
-#ifdef XP_MACOSX
-    // The quartz image surface (ab)uses the flush method to get the
-    // cairo_image_surface data into a CGImage, so we have to call Flush() here.
-    if (mQuartzSurface)
-      mQuartzSurface->Flush();
-#endif
-
-    mDirty = false;
-  }
-}
-
 void imgFrame::SetDiscardable()
 {
   MOZ_ASSERT(mLockCount, "Expected to be locked when SetDiscardable is called");
   // Disabled elsewhere due to the cost of calling GetSourceSurfaceForSurface.
 #ifdef MOZ_WIDGET_ANDROID
   mDiscardable = true;
 #endif
 }
 
+TemporaryRef<SourceSurface>
+imgFrame::GetSurface()
+{
+  if (mOptSurface) {
+    if (mOptSurface->IsValid())
+      return mOptSurface;
+    else
+      mOptSurface = nullptr;
+  }
+
+  if (mImageSurface)
+    return mImageSurface;
+
+  if (!mVBuf)
+    return nullptr;
+
+  VolatileBufferPtr<char> buf(mVBuf);
+  if (buf.WasBufferPurged())
+    return nullptr;
+
+  return CreateLockedSurface(mVBuf, mSize, mFormat);
+}
+
 int32_t imgFrame::GetRawTimeout() const
 {
   return mTimeout;
 }
 
 void imgFrame::SetRawTimeout(int32_t aTimeout)
 {
   mTimeout = aTimeout;
@@ -885,33 +702,32 @@ int32_t imgFrame::GetBlendMethod() const
 void imgFrame::SetBlendMethod(int32_t aBlendMethod)
 {
   mBlendMethod = (int8_t)aBlendMethod;
 }
 
 // This can be called from any thread.
 bool imgFrame::ImageComplete() const
 {
-  MutexAutoLock lock(mDirtyMutex);
+  MutexAutoLock lock(mDecodedMutex);
 
-  return mDecoded.IsEqualInterior(nsIntRect(mOffset, mSize));
+  return mDecoded.IsEqualInterior(nsIntRect(mOffset.x, mOffset.y,
+                                            mSize.width, mSize.height));
 }
 
 // A hint from the image decoders that this image has no alpha, even
 // though we created is ARGB32.  This changes our format to RGB24,
 // which in turn will cause us to Optimize() to RGB24.  Has no effect
 // after Optimize() is called, though in all cases it will be just a
 // performance win -- the pixels are still correct and have the A byte
 // set to 0xff.
 void imgFrame::SetHasNoAlpha()
 {
-  if (mFormat == gfxImageFormat::ARGB32) {
-      mFormat = gfxImageFormat::RGB24;
-      mFormatChanged = true;
-      ThebesSurface()->SetOpaqueRect(gfxRect(0, 0, mSize.width, mSize.height));
+  if (mFormat == SurfaceFormat::B8G8R8A8) {
+    mFormat = SurfaceFormat::B8G8R8X8;
   }
 }
 
 void imgFrame::SetAsNonPremult(bool aIsNonPremult)
 {
   mNonPremult = aIsNonPremult;
 }
 
@@ -943,53 +759,26 @@ imgFrame::SizeOfExcludingThisWithCompute
   if (mPalettedImageData && aLocation == gfxMemoryLocation::IN_PROCESS_HEAP) {
     size_t n2 = aMallocSizeOf(mPalettedImageData);
     if (n2 == 0) {
       n2 = GetImageDataLength() + PaletteDataLength();
     }
     n += n2;
   }
 
-#ifdef USE_WIN_SURFACE
-  if (mWinSurface && aLocation == mWinSurface->GetMemoryLocation()) {
-    n += mWinSurface->KnownMemoryUsed();
-  } else
-#endif
-#ifdef XP_MACOSX
-  if (mQuartzSurface && aLocation == gfxMemoryLocation::IN_PROCESS_HEAP) {
-    n += aMallocSizeOf(mQuartzSurface);
+  if (mImageSurface && aLocation == gfxMemoryLocation::IN_PROCESS_HEAP) {
+    n += aMallocSizeOf(mImageSurface);
   }
-#endif
-  if (mImageSurface && aLocation == mImageSurface->GetMemoryLocation()) {
-    size_t n2 = 0;
-    if (aLocation == gfxMemoryLocation::IN_PROCESS_HEAP) { // HEAP: measure
-      n2 = mImageSurface->SizeOfIncludingThis(aMallocSizeOf);
-    }
-    if (n2 == 0) {  // non-HEAP or computed fallback for HEAP
-      n2 = mImageSurface->KnownMemoryUsed();
-    }
-    n += n2;
+  if (mOptSurface && aLocation == gfxMemoryLocation::IN_PROCESS_HEAP) {
+    n += aMallocSizeOf(mOptSurface);
   }
 
   if (mVBuf && aLocation == gfxMemoryLocation::IN_PROCESS_HEAP) {
     n += aMallocSizeOf(mVBuf);
     n += mVBuf->HeapSizeOfExcludingThis(aMallocSizeOf);
   }
 
   if (mVBuf && aLocation == gfxMemoryLocation::IN_PROCESS_NONHEAP) {
     n += mVBuf->NonHeapSizeOfExcludingThis();
   }
 
-  if (mOptSurface && aLocation == mOptSurface->GetMemoryLocation()) {
-    size_t n2 = 0;
-    if (aLocation == gfxMemoryLocation::IN_PROCESS_HEAP &&
-        mOptSurface->SizeOfIsMeasured()) {
-      // HEAP: measure (but only if the sub-class is capable of measuring)
-      n2 = mOptSurface->SizeOfIncludingThis(aMallocSizeOf);
-    }
-    if (n2 == 0) {  // non-HEAP or computed fallback for HEAP
-      n2 = mOptSurface->KnownMemoryUsed();
-    }
-    n += n2;
-  }
-
   return n;
 }
--- a/image/src/imgFrame.h
+++ b/image/src/imgFrame.h
@@ -5,65 +5,43 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef imgFrame_h
 #define imgFrame_h
 
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/VolatileBuffer.h"
-#include "nsRect.h"
-#include "nsPoint.h"
-#include "nsSize.h"
-#include "gfxPattern.h"
 #include "gfxDrawable.h"
-#include "gfxImageSurface.h"
-#if defined(XP_WIN)
-#include "gfxWindowsSurface.h"
-#elif defined(XP_MACOSX)
-#include "gfxQuartzImageSurface.h"
-#endif
-#include "nsAutoPtr.h"
 #include "imgIContainer.h"
-#include "gfxColor.h"
-
-/*
- * This creates a gfxImageSurface which will unlock the buffer on destruction
- */
-
-class LockedImageSurface
-{
-public:
-  static gfxImageSurface *
-  CreateSurface(mozilla::VolatileBuffer *vbuf,
-                const gfxIntSize& size,
-                gfxImageFormat format);
-  static mozilla::TemporaryRef<mozilla::VolatileBuffer>
-  AllocateBuffer(const gfxIntSize& size, gfxImageFormat format);
-};
 
 class imgFrame
 {
+  typedef mozilla::gfx::Color Color;
+  typedef mozilla::gfx::DataSourceSurface DataSourceSurface;
+  typedef mozilla::gfx::IntSize IntSize;
+  typedef mozilla::gfx::SourceSurface SourceSurface;
+  typedef mozilla::gfx::SurfaceFormat SurfaceFormat;
+
 public:
   imgFrame();
   ~imgFrame();
 
-  nsresult Init(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight, gfxImageFormat aFormat, uint8_t aPaletteDepth = 0);
+  nsresult Init(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight, mozilla::gfx::SurfaceFormat aFormat, uint8_t aPaletteDepth = 0);
   nsresult Optimize();
 
   bool Draw(gfxContext *aContext, GraphicsFilter aFilter,
             const gfxMatrix &aUserSpaceToImageSpace, const gfxRect& aFill,
             const nsIntMargin &aPadding, const nsIntRect &aSubimage,
             uint32_t aImageFlags = imgIContainer::FLAG_NONE);
 
   nsresult ImageUpdated(const nsIntRect &aUpdateRect);
-  bool GetIsDirty() const;
 
   nsIntRect GetRect() const;
-  gfxImageFormat GetFormat() const;
+  mozilla::gfx::SurfaceFormat GetFormat() const;
   bool GetNeedsBackground() const;
   uint32_t GetImageBytesPerRow() const;
   uint32_t GetImageDataLength() const;
   bool GetIsPaletted() const;
   bool GetHasAlpha() const;
   void GetImageData(uint8_t **aData, uint32_t *length) const;
   uint8_t* GetImageData() const;
   void GetPaletteData(uint32_t **aPalette, uint32_t *length) const;
@@ -81,88 +59,33 @@ public:
   void SetHasNoAlpha();
   void SetAsNonPremult(bool aIsNonPremult);
 
   bool GetCompositingFailed() const;
   void SetCompositingFailed(bool val);
 
   nsresult LockImageData();
   nsresult UnlockImageData();
-  void ApplyDirtToSurfaces();
 
   void SetDiscardable();
 
-  nsresult GetSurface(gfxASurface **aSurface)
-  {
-    *aSurface = ThebesSurface();
-    NS_IF_ADDREF(*aSurface);
-    return NS_OK;
-  }
+  mozilla::TemporaryRef<SourceSurface> GetSurface();
 
-  nsresult GetPattern(gfxPattern **aPattern)
+  Color
+  SinglePixelColor()
   {
-    if (mSinglePixel)
-      *aPattern = new gfxPattern(mSinglePixelColor);
-    else
-      *aPattern = new gfxPattern(ThebesSurface());
-    NS_ADDREF(*aPattern);
-    return NS_OK;
+    return mSinglePixelColor;
   }
 
   bool IsSinglePixel()
   {
     return mSinglePixel;
   }
 
-  gfxASurface* CachedThebesSurface()
-  {
-    if (mOptSurface)
-      return mOptSurface;
-#if defined(XP_WIN)
-    if (mWinSurface)
-      return mWinSurface;
-#elif defined(XP_MACOSX)
-    if (mQuartzSurface)
-      return mQuartzSurface;
-#endif
-    if (mImageSurface)
-      return mImageSurface;
-    return nullptr;
-  }
-
-  gfxASurface* ThebesSurface()
-  {
-    gfxASurface *sur = CachedThebesSurface();
-    if (sur)
-      return sur;
-    if (mVBuf) {
-      mozilla::VolatileBufferPtr<uint8_t> ref(mVBuf);
-      if (ref.WasBufferPurged())
-        return nullptr;
-
-      gfxImageSurface *imgSur =
-        LockedImageSurface::CreateSurface(mVBuf, mSize, mFormat);
-#if defined(XP_MACOSX)
-      // Manually addref and release to make sure the cairo surface isn't lost
-      NS_ADDREF(imgSur);
-      gfxQuartzImageSurface *quartzSur = new gfxQuartzImageSurface(imgSur);
-      // quartzSur does not hold on to the gfxImageSurface
-      NS_RELEASE(imgSur);
-      return quartzSur;
-#else
-      return imgSur;
-#endif
-    }
-    // We can return null here if we're single pixel optimized
-    // or a paletted image. However, one has to check for paletted
-    // image data first before attempting to get a surface, so
-    // this is only valid for single pixel optimized images
-    MOZ_ASSERT(mSinglePixel, "No image surface and not a single pixel!");
-    return nullptr;
-  }
+  mozilla::TemporaryRef<SourceSurface> CachedSurface();
 
   size_t SizeOfExcludingThisWithComputedFallbackIfHeap(
            gfxMemoryLocation aLocation,
            mozilla::MallocSizeOf aMallocSizeOf) const;
 
   uint8_t GetPaletteDepth() const { return mPaletteDepth; }
   uint32_t PaletteDataLength() const {
     if (!mPaletteDepth)
@@ -170,82 +93,73 @@ public:
 
     return ((1 << mPaletteDepth) * sizeof(uint32_t));
   }
 
 private: // methods
 
   struct SurfaceWithFormat {
     nsRefPtr<gfxDrawable> mDrawable;
-    gfxImageFormat mFormat;
+    SurfaceFormat mFormat;
     SurfaceWithFormat() {}
-    SurfaceWithFormat(gfxDrawable* aDrawable, gfxImageFormat aFormat)
+    SurfaceWithFormat(gfxDrawable* aDrawable, SurfaceFormat aFormat)
      : mDrawable(aDrawable), mFormat(aFormat) {}
     bool IsValid() { return !!mDrawable; }
   };
 
   SurfaceWithFormat SurfaceForDrawing(bool               aDoPadding,
                                       bool               aDoPartialDecode,
                                       bool               aDoTile,
                                       const nsIntMargin& aPadding,
                                       gfxMatrix&         aUserSpaceToImageSpace,
                                       gfxRect&           aFill,
                                       gfxRect&           aSubimage,
                                       gfxRect&           aSourceRect,
                                       gfxRect&           aImageRect,
-                                      gfxASurface*       aSurface);
+                                      SourceSurface*     aSurface);
 
 private: // data
-  nsRefPtr<gfxImageSurface> mImageSurface;
-  nsRefPtr<gfxASurface> mOptSurface;
-#if defined(XP_WIN)
-  nsRefPtr<gfxWindowsSurface> mWinSurface;
-#elif defined(XP_MACOSX)
-  nsRefPtr<gfxQuartzImageSurface> mQuartzSurface;
-#endif
+  mozilla::RefPtr<DataSourceSurface> mImageSurface;
+  mozilla::RefPtr<SourceSurface> mOptSurface;
 
-  nsRefPtr<gfxASurface> mDrawSurface;
-
-  nsIntSize    mSize;
+  IntSize      mSize;
   nsIntPoint   mOffset;
 
   nsIntRect    mDecoded;
 
-  mutable mozilla::Mutex mDirtyMutex;
+  mutable mozilla::Mutex mDecodedMutex;
 
   // The palette and image data for images that are paletted, since Cairo
   // doesn't support these images.
   // The paletted data comes first, then the image data itself.
   // Total length is PaletteDataLength() + GetImageDataLength().
   uint8_t*     mPalettedImageData;
 
-  // Note that the data stored in gfxRGBA is *non-alpha-premultiplied*.
-  gfxRGBA      mSinglePixelColor;
+  // Note that the data stored in gfx::Color is *non-alpha-premultiplied*.
+  Color        mSinglePixelColor;
 
   int32_t      mTimeout; // -1 means display forever
   int32_t      mDisposalMethod;
 
   /** Indicates how many readers currently have locked this frame */
   int32_t mLockCount;
 
   mozilla::RefPtr<mozilla::VolatileBuffer> mVBuf;
+  mozilla::VolatileBufferPtr<uint8_t> mVBufPtr;
 
-  gfxImageFormat mFormat;
+  SurfaceFormat mFormat;
   uint8_t      mPaletteDepth;
   int8_t       mBlendMethod;
   bool mSinglePixel;
-  bool mFormatChanged;
   bool mCompositingFailed;
   bool mNonPremult;
   bool mDiscardable;
 
   /** Have we called DiscardTracker::InformAllocation()? */
   bool mInformedDiscardTracker;
-
-  bool mDirty;
 };
 
 namespace mozilla {
 namespace image {
   // An RAII class to ensure it's easy to balance locks and unlocks on
   // imgFrames.
   class AutoFrameLocker
   {
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -5048,17 +5048,17 @@ nsLayoutUtils::DrawPixelSnapped(nsRender
                    drawingParams.mSubimage.width, drawingParams.mSubimage.height);
 
   NS_ASSERTION(!sourceRect.Intersect(subimage).IsEmpty(),
                "We must be allowed to sample *some* source pixels!");
 
   gfxUtils::DrawPixelSnapped(ctx, aDrawable,
                              drawingParams.mUserSpaceToImageSpace, subimage,
                              sourceRect, imageRect, drawingParams.mFillRect,
-                             gfxImageFormat::ARGB32, aFilter);
+                             gfx::SurfaceFormat::B8G8R8A8, aFilter);
 }
 
 /* static */ nsresult
 nsLayoutUtils::DrawSingleUnscaledImage(nsRenderingContext* aRenderingContext,
                                        imgIContainer*       aImage,
                                        GraphicsFilter       aGraphicsFilter,
                                        const nsPoint&       aDest,
                                        const nsRect*        aDirty,