Bug 959526 - Implement PlanarYCrCbImage and derived classes GetAsSourceSurface. r=nical
authorAli Akhtarzada <ali@comoyo.com>
Tue, 21 Jan 2014 11:49:53 -0500
changeset 180495 e9615b0981fe6541882088d77f5c50656927215f
parent 180494 60698fb6579b810bf27ba77bdce080c02787694d
child 180496 592066fa82d29f287a401d584ea299bf919c5dce
push idunknown
push userunknown
push dateunknown
reviewersnical
bugs959526
milestone29.0a1
Bug 959526 - Implement PlanarYCrCbImage and derived classes GetAsSourceSurface. r=nical Implement GetAsSourceSurface in: * PlanarYCrCbImage * BasicPlanarYCrCbImage * SharedPlanarYCrCbImage
gfx/layers/ImageContainer.cpp
gfx/layers/ImageContainer.h
gfx/layers/basic/BasicImages.cpp
gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
gfx/layers/ipc/SharedPlanarYCbCrImage.h
--- a/gfx/layers/ImageContainer.cpp
+++ b/gfx/layers/ImageContainer.cpp
@@ -630,18 +630,18 @@ PlanarYCbCrImage::AllocateAndGetNewBuffe
     mBufferSize = aSize;
   }
   return mBuffer;
 }
 
 already_AddRefed<gfxASurface>
 PlanarYCbCrImage::DeprecatedGetAsSurface()
 {
-  if (mSurface) {
-    nsRefPtr<gfxASurface> result = mSurface.get();
+  if (mDeprecatedSurface) {
+    nsRefPtr<gfxASurface> result = mDeprecatedSurface.get();
     return result.forget();
   }
 
   gfx::SurfaceFormat format = gfx::ImageFormatToSurfaceFormat(GetOffscreenFormat());
   gfx::IntSize size(mSize);
   gfx::GetYCbCrToRGBDestFormatAndSize(mData, format, size);
   if (size.width > PlanarYCbCrImage::MAX_DIMENSION ||
       size.height > PlanarYCbCrImage::MAX_DIMENSION) {
@@ -649,21 +649,46 @@ PlanarYCbCrImage::DeprecatedGetAsSurface
     return nullptr;
   }
 
   nsRefPtr<gfxImageSurface> imageSurface =
     new gfxImageSurface(gfx::ThebesIntSize(mSize), gfx::SurfaceFormatToImageFormat(format));
 
   gfx::ConvertYCbCrToRGB(mData, format, mSize, imageSurface->Data(), imageSurface->Stride());
 
-  mSurface = imageSurface;
+  mDeprecatedSurface = imageSurface;
 
   return imageSurface.forget();
 }
 
+TemporaryRef<gfx::SourceSurface>
+PlanarYCbCrImage::GetAsSourceSurface()
+{
+  if (mSourceSurface) {
+    return mSourceSurface.get();
+  }
+
+  gfx::IntSize size(mSize);
+  gfx::SurfaceFormat format = gfx::ImageFormatToSurfaceFormat(GetOffscreenFormat());
+  gfx::GetYCbCrToRGBDestFormatAndSize(mData, format, size);
+  if (mSize.width > PlanarYCbCrImage::MAX_DIMENSION ||
+      mSize.height > PlanarYCbCrImage::MAX_DIMENSION) {
+    NS_ERROR("Illegal image dest width or height");
+    return nullptr;
+  }
+
+  RefPtr<gfx::DataSourceSurface> surface = gfx::Factory::CreateDataSourceSurface(size, format);
+
+  gfx::ConvertYCbCrToRGB(mData, format, size, surface->GetData(), surface->Stride());
+
+  mSourceSurface = surface;
+
+  return surface.forget();
+}
+
 already_AddRefed<gfxASurface>
 RemoteBitmapImage::DeprecatedGetAsSurface()
 {
   nsRefPtr<gfxImageSurface> newSurf =
     new gfxImageSurface(ThebesIntSize(mSize),
     mFormat == RemoteImageData::BGRX32 ? gfxImageFormatRGB24 : gfxImageFormatARGB32);
 
   for (int y = 0; y < mSize.height; y++) {
--- a/gfx/layers/ImageContainer.h
+++ b/gfx/layers/ImageContainer.h
@@ -897,26 +897,28 @@ protected:
   /**
    * Return a buffer to store image data in.
    * The default implementation returns memory that can
    * be freed wit delete[]
    */
   virtual uint8_t* AllocateBuffer(uint32_t aSize);
 
   already_AddRefed<gfxASurface> DeprecatedGetAsSurface();
+  TemporaryRef<gfx::SourceSurface> GetAsSourceSurface();
 
   void SetOffscreenFormat(gfxImageFormat aFormat) { mOffscreenFormat = aFormat; }
   gfxImageFormat GetOffscreenFormat();
 
   nsAutoArrayPtr<uint8_t> mBuffer;
   uint32_t mBufferSize;
   Data mData;
   gfx::IntSize mSize;
   gfxImageFormat mOffscreenFormat;
-  nsCountedRef<nsMainThreadSurfaceRef> mSurface;
+  nsCountedRef<nsMainThreadSurfaceRef> mDeprecatedSurface;
+  nsCountedRef<nsMainThreadSourceSurfaceRef> mSourceSurface;
   nsRefPtr<BufferRecycleBin> mRecycleBin;
 };
 
 /**
  * Currently, the data in a CairoImage surface is treated as being in the
  * device output color space. This class is very simple as all backends
  * have to know about how to deal with drawing a cairo image.
  */
--- a/gfx/layers/basic/BasicImages.cpp
+++ b/gfx/layers/basic/BasicImages.cpp
@@ -48,16 +48,17 @@ public:
       mRecycleBin->RecycleBuffer(mDecodedBuffer.forget(), mSize.height * mStride);
     }
   }
 
   virtual void SetData(const Data& aData);
   virtual void SetDelayedConversion(bool aDelayed) { mDelayedConversion = aDelayed; }
 
   already_AddRefed<gfxASurface> DeprecatedGetAsSurface();
+  TemporaryRef<gfx::SourceSurface> GetAsSourceSurface();
 
 private:
   nsAutoArrayPtr<uint8_t> mDecodedBuffer;
   gfx::IntSize mScaleHint;
   int mStride;
   bool mDelayedConversion;
 };
 
@@ -132,18 +133,18 @@ DestroyBuffer(void* aBuffer)
   delete[] static_cast<uint8_t*>(aBuffer);
 }
 
 already_AddRefed<gfxASurface>
 BasicPlanarYCbCrImage::DeprecatedGetAsSurface()
 {
   NS_ASSERTION(NS_IsMainThread(), "Must be main thread");
 
-  if (mSurface) {
-    nsRefPtr<gfxASurface> result = mSurface.get();
+  if (mDeprecatedSurface) {
+    nsRefPtr<gfxASurface> result = mDeprecatedSurface.get();
     return result.forget();
   }
 
   if (!mDecodedBuffer) {
     return PlanarYCbCrImage::DeprecatedGetAsSurface();
   }
 
   gfxImageFormat format = GetOffscreenFormat();
@@ -161,21 +162,60 @@ BasicPlanarYCbCrImage::DeprecatedGetAsSu
 #if defined(XP_MACOSX)
   nsRefPtr<gfxQuartzImageSurface> quartzSurface =
     new gfxQuartzImageSurface(imgSurface);
   if (quartzSurface) {
     result = quartzSurface.forget();
   }
 #endif
 
-  mSurface = result;
+  mDeprecatedSurface = result;
 
   return result.forget();
 }
 
+TemporaryRef<gfx::SourceSurface>
+BasicPlanarYCbCrImage::GetAsSourceSurface()
+{
+  NS_ASSERTION(NS_IsMainThread(), "Must be main thread");
+
+  if (mSourceSurface) {
+    return mSourceSurface.get();
+  }
+
+  if (!mDecodedBuffer) {
+    return PlanarYCbCrImage::GetAsSourceSurface();
+  }
+
+  gfxImageFormat format = GetOffscreenFormat();
+
+  RefPtr<gfx::SourceSurface> surface;
+  {
+    // Create a DrawTarget so that we can own the data inside mDecodeBuffer.
+    // We create the target out of mDecodedBuffer, and get a snapshot from it.
+    // The draw target is destroyed on scope exit and the surface owns the data.
+    RefPtr<gfx::DrawTarget> drawTarget
+      = gfxPlatform::GetPlatform()->CreateDrawTargetForData(mDecodedBuffer,
+                                                            mSize,
+                                                            mStride,
+                                                            gfx::ImageFormatToSurfaceFormat(format));
+    if (!drawTarget) {
+      return nullptr;
+    }
+
+    surface = drawTarget->Snapshot();
+  }
+
+  mRecycleBin->RecycleBuffer(mDecodedBuffer.forget(), mSize.height * mStride);
+
+  mSourceSurface = surface;
+  return mSourceSurface.get();
+}
+
+
 ImageFactory*
 BasicLayerManager::GetImageFactory()
 {
   if (!mFactory) {
     mFactory = new BasicImageFactory();
   }
 
   return mFactory.get();
--- a/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
+++ b/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
@@ -79,16 +79,26 @@ SharedPlanarYCbCrImage::DeprecatedGetAsS
 {
   if (!mTextureClient->IsAllocated()) {
     NS_WARNING("Can't get as surface");
     return nullptr;
   }
   return PlanarYCbCrImage::DeprecatedGetAsSurface();
 }
 
+TemporaryRef<gfx::SourceSurface>
+SharedPlanarYCbCrImage::GetAsSourceSurface()
+{
+  if (!mTextureClient->IsAllocated()) {
+    NS_WARNING("Can't get as surface");
+    return nullptr;
+  }
+  return PlanarYCbCrImage::GetAsSourceSurface();
+}
+
 void
 SharedPlanarYCbCrImage::SetData(const PlanarYCbCrData& aData)
 {
   // If mShmem has not been allocated (through Allocate(aData)), allocate it.
   // This code path is slower than the one used when Allocate has been called
   // since it will trigger a full copy.
   if (!mTextureClient->IsAllocated()) {
     Data data = aData;
--- a/gfx/layers/ipc/SharedPlanarYCbCrImage.h
+++ b/gfx/layers/ipc/SharedPlanarYCbCrImage.h
@@ -96,16 +96,17 @@ public:
   SharedPlanarYCbCrImage(ImageClient* aCompositable);
   ~SharedPlanarYCbCrImage();
 
   virtual ISharedImage* AsSharedImage() MOZ_OVERRIDE { return this; }
   virtual TextureClient* GetTextureClient() MOZ_OVERRIDE;
   virtual uint8_t* GetBuffer() MOZ_OVERRIDE;
 
   virtual already_AddRefed<gfxASurface> DeprecatedGetAsSurface() MOZ_OVERRIDE;
+  virtual TemporaryRef<gfx::SourceSurface> GetAsSourceSurface() MOZ_OVERRIDE;
   virtual void SetData(const PlanarYCbCrData& aData) MOZ_OVERRIDE;
   virtual void SetDataNoCopy(const Data &aData) MOZ_OVERRIDE;
 
   virtual bool Allocate(PlanarYCbCrData& aData);
   virtual uint8_t* AllocateBuffer(uint32_t aSize) MOZ_OVERRIDE;
   // needs to be overriden because the parent class sets mBuffer which we
   // do not want to happen.
   virtual uint8_t* AllocateAndGetNewBuffer(uint32_t aSize) MOZ_OVERRIDE;