Bug 975900 - Convert imgUtils to Moz2D (from gfxASurface to SourceSurface). r=mattwoodrow
authorJonathan Watt <jwatt@jwatt.org>
Tue, 25 Feb 2014 00:51:45 +0000
changeset 170652 8a109eb551fcf517d6b1c0e04e2296c7920267e2
parent 170651 5492ecd562f9d9058001a6f225536658ff8dd89d
child 170653 775ed04f9f491de675657657f8fd928062ad3d0b
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewersmattwoodrow
bugs975900
milestone30.0a1
Bug 975900 - Convert imgUtils to Moz2D (from gfxASurface to SourceSurface). r=mattwoodrow
gfx/thebes/gfxImageSurface.cpp
gfx/thebes/gfxImageSurface.h
image/src/imgTools.cpp
image/src/imgTools.h
--- a/gfx/thebes/gfxImageSurface.cpp
+++ b/gfx/thebes/gfxImageSurface.cpp
@@ -312,16 +312,28 @@ gfxImageSurface::CopyTo(SourceSurface *a
         return false;
     }
 
     CopyForStride(data->GetData(), mData, size, data->Stride(), mStride);
 
     return true;
 }
 
+TemporaryRef<DataSourceSurface>
+gfxImageSurface::CopyToB8G8R8A8DataSourceSurface()
+{
+  RefPtr<DataSourceSurface> dataSurface =
+    Factory::CreateDataSourceSurface(IntSize(GetSize().width, GetSize().height),
+                                     SurfaceFormat::B8G8R8A8);
+  if (dataSurface) {
+    CopyTo(dataSurface);
+  }
+  return dataSurface.forget();
+}
+
 already_AddRefed<gfxSubimageSurface>
 gfxImageSurface::GetSubimage(const gfxRect& aRect)
 {
     gfxRect r(aRect);
     r.Round();
     MOZ_ASSERT(gfxRect(0, 0, mSize.width, mSize.height).Contains(r));
 
     gfxImageFormat format = Format();
--- a/gfx/thebes/gfxImageSurface.h
+++ b/gfx/thebes/gfxImageSurface.h
@@ -2,26 +2,28 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_IMAGESURFACE_H
 #define GFX_IMAGESURFACE_H
 
 #include "mozilla/MemoryReporting.h"
+#include "mozilla/RefPtr.h"
 #include "gfxASurface.h"
 #include "nsAutoPtr.h"
 #include "nsSize.h"
 
 // ARGB -- raw buffer.. wont be changed.. good for storing data.
 
 class gfxSubimageSurface;
 
 namespace mozilla {
 namespace gfx {
+class DataSourceSurface;
 class SourceSurface;
 }
 }
 
 /**
  * A raw image buffer. The format can be set in the constructor. Its main
  * purpose is for storing read-only images and using it as a source surface,
  * but it can also be drawn to.
@@ -103,16 +105,21 @@ public:
     bool CopyFrom (mozilla::gfx::SourceSurface *aSurface);
 
     /**
      * Fast copy to a source surface; returns TRUE if successful, FALSE otherwise
      * Assumes that the format of this surface is compatible with aSurface
      */
     bool CopyTo (mozilla::gfx::SourceSurface *aSurface);
 
+    /**
+     * Copy to a Moz2D DataSourceSurface.
+     */
+    mozilla::TemporaryRef<mozilla::gfx::DataSourceSurface> CopyToB8G8R8A8DataSourceSurface();
+
     /* return new Subimage with pointing to original image starting from aRect.pos
      * and size of aRect.size. New subimage keeping current image reference
      */
     already_AddRefed<gfxSubimageSurface> GetSubimage(const gfxRect& aRect);
 
     virtual already_AddRefed<gfxImageSurface> GetAsImageSurface();
 
     /** See gfxASurface.h. */
--- a/image/src/imgTools.cpp
+++ b/image/src/imgTools.cpp
@@ -1,28 +1,27 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "imgTools.h"
 
+#include "mozilla/gfx/2D.h"
+#include "mozilla/RefPtr.h"
 #include "nsCOMPtr.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsError.h"
 #include "imgLoader.h"
 #include "imgICache.h"
 #include "imgIContainer.h"
 #include "imgIEncoder.h"
-#include "gfxContext.h"
-#include "nsComponentManagerUtils.h"
 #include "nsStreamUtils.h"
-#include "nsNetUtil.h"
 #include "nsContentUtils.h"
 #include "ImageFactory.h"
 #include "Image.h"
 #include "ScriptedNotificationObserver.h"
 #include "imgIScriptedNotificationObserver.h"
 #include "gfxPlatform.h"
 
 using namespace mozilla;
@@ -93,30 +92,87 @@ NS_IMETHODIMP imgTools::DecodeImage(nsII
   rv = image->OnImageDataComplete(nullptr, nullptr, NS_OK, true);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // All done.
   NS_ADDREF(*aContainer = image.get());
   return NS_OK;
 }
 
+static TemporaryRef<SourceSurface>
+GetFirstImageFrame(imgIContainer *aContainer)
+{
+  nsRefPtr<gfxASurface> frame =
+    aContainer->GetFrame(imgIContainer::FRAME_FIRST,
+                         imgIContainer::FLAG_SYNC_DECODE);
+  NS_ENSURE_TRUE(frame, nullptr);
+
+  nsRefPtr<gfxImageSurface> imageSurface = frame->CopyToARGB32ImageSurface();
+  NS_ENSURE_TRUE(imageSurface, nullptr);
+
+  return imageSurface->CopyToB8G8R8A8DataSourceSurface();
+}
+
+/**
+ * This takes a DataSourceSurface rather than a SourceSurface because some
+ * of the callers have a DataSourceSurface and we don't want to call
+ * GetDataSurface on such surfaces since that may incure a conversion to
+ * SurfaceType::DATA which we don't need.
+ */
+static nsresult EncodeImageData(DataSourceSurface* aDataSurface,
+                                const nsACString& aMimeType,
+                                const nsAString& aOutputOptions,
+                                nsIInputStream **aStream)
+{
+  MOZ_ASSERT(aDataSurface->GetFormat() ==  SurfaceFormat::B8G8R8A8,
+             "We're assuming B8G8R8A8");
+
+  // Get an image encoder for the media type
+  nsAutoCString encoderCID(
+    NS_LITERAL_CSTRING("@mozilla.org/image/encoder;2?type=") + aMimeType);
+
+  nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(encoderCID.get());
+  if (!encoder)
+    return NS_IMAGELIB_ERROR_NO_ENCODER;
+
+  DataSourceSurface::MappedSurface map;
+  aDataSurface->Map(DataSourceSurface::MapType::READ, &map);
+  if (!map.mData)
+    return NS_ERROR_FAILURE;
+
+  IntSize size = aDataSurface->GetSize();
+  uint32_t dataLength = map.mStride * size.height;
+
+  // Encode the bitmap
+  nsresult rv = encoder->InitFromData(map.mData,
+                                      dataLength,
+                                      size.width,
+                                      size.height,
+                                      map.mStride,
+                                      imgIEncoder::INPUT_FORMAT_HOSTARGB,
+                                      aOutputOptions);
+
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return CallQueryInterface(encoder, aStream);
+}
 
 NS_IMETHODIMP imgTools::EncodeImage(imgIContainer *aContainer,
                                     const nsACString& aMimeType,
                                     const nsAString& aOutputOptions,
                                     nsIInputStream **aStream)
 {
-  nsresult rv;
+  // Use frame 0 from the image container.
+  RefPtr<SourceSurface> frame = GetFirstImageFrame(aContainer);
+  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
 
-  // Use frame 0 from the image container.
-  nsRefPtr<gfxImageSurface> frame;
-  rv = GetFirstImageFrame(aContainer, getter_AddRefs(frame));
-  NS_ENSURE_SUCCESS(rv, rv);
+  RefPtr<DataSourceSurface> dataSurface = frame->GetDataSurface();
+  NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);
 
-  return EncodeImageData(frame, aMimeType, aOutputOptions, aStream);
+  return EncodeImageData(dataSurface, aMimeType, aOutputOptions, aStream);
 }
 
 NS_IMETHODIMP imgTools::EncodeScaledImage(imgIContainer *aContainer,
                                           const nsACString& aMimeType,
                                           int32_t aScaledWidth,
                                           int32_t aScaledHeight,
                                           const nsAString& aOutputOptions,
                                           nsIInputStream **aStream)
@@ -125,62 +181,51 @@ NS_IMETHODIMP imgTools::EncodeScaledImag
 
   // If no scaled size is specified, we'll just encode the image at its
   // original size (no scaling).
   if (aScaledWidth == 0 && aScaledHeight == 0) {
     return EncodeImage(aContainer, aMimeType, aOutputOptions, aStream);
   }
 
   // Use frame 0 from the image container.
-  nsRefPtr<gfxImageSurface> frame;
-  nsresult rv = GetFirstImageFrame(aContainer, getter_AddRefs(frame));
-  NS_ENSURE_SUCCESS(rv, rv);
+  RefPtr<SourceSurface> frame = GetFirstImageFrame(aContainer);
+  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
 
-  int32_t frameWidth = frame->Width(), frameHeight = frame->Height();
+  int32_t frameWidth = frame->GetSize().width;
+  int32_t frameHeight = frame->GetSize().height;
 
   // If the given width or height is zero we'll replace it with the image's
   // original dimensions.
   if (aScaledWidth == 0) {
     aScaledWidth = frameWidth;
   } else if (aScaledHeight == 0) {
     aScaledHeight = frameHeight;
   }
 
-  // Create a temporary image surface
-  nsRefPtr<gfxImageSurface> dest = new gfxImageSurface(gfxIntSize(aScaledWidth, aScaledHeight),
-                                                       gfxImageFormat::ARGB32);
-  if (gfxPlatform::GetPlatform()->SupportsAzureContent()) {
-    RefPtr<DrawTarget> dt =
-      gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(dest, IntSize(aScaledWidth, aScaledHeight));
-    RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, frame);
-
-    dt->DrawSurface(source,
-                    Rect(0, 0, aScaledWidth, aScaledHeight),
-                    Rect(0, 0, frameWidth, frameHeight),
-                    DrawSurfaceOptions(),
-                    DrawOptions(1.0f, CompositionOp::OP_SOURCE));
-  } else {
-    gfxContext ctx(dest);
+  RefPtr<DataSourceSurface> dataSurface =
+    Factory::CreateDataSourceSurface(IntSize(aScaledWidth, aScaledHeight),
+                                     SurfaceFormat::B8G8R8A8);
+  DataSourceSurface::MappedSurface map;
+  dataSurface->Map(DataSourceSurface::MapType::WRITE, &map);
+  if (!map.mData)
+    return NS_ERROR_FAILURE;
 
-    // Set scaling
-    gfxFloat sw = (double) aScaledWidth / frameWidth;
-    gfxFloat sh = (double) aScaledHeight / frameHeight;
-    ctx.Scale(sw, sh);
-
-    // Paint a scaled image
-    ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
+  RefPtr<DrawTarget> dt =
+    Factory::CreateDrawTargetForData(BackendType::CAIRO,
+                                     map.mData,
+                                     dataSurface->GetSize(),
+                                     map.mStride,
+                                     SurfaceFormat::B8G8R8A8);
+  dt->DrawSurface(frame,
+                  Rect(0, 0, aScaledWidth, aScaledHeight),
+                  Rect(0, 0, frameWidth, frameHeight),
+                  DrawSurfaceOptions(),
+                  DrawOptions(1.0f, CompositionOp::OP_SOURCE));
 
-    nsRefPtr<gfxPattern> pat = new gfxPattern(frame);
-    pat->SetExtend(gfxPattern::EXTEND_PAD);
-    ctx.SetPattern(pat);
-    ctx.Paint();
-  }
-
-
-  return EncodeImageData(dest, aMimeType, aOutputOptions, aStream);
+  return EncodeImageData(dataSurface, aMimeType, aOutputOptions, aStream);
 }
 
 NS_IMETHODIMP imgTools::EncodeCroppedImage(imgIContainer *aContainer,
                                            const nsACString& aMimeType,
                                            int32_t aOffsetX,
                                            int32_t aOffsetY,
                                            int32_t aWidth,
                                            int32_t aHeight,
@@ -195,103 +240,53 @@ NS_IMETHODIMP imgTools::EncodeCroppedIma
 
   // If no size is specified then we'll preserve the image's original dimensions
   // and don't need to crop.
   if (aWidth == 0 && aHeight == 0) {
     return EncodeImage(aContainer, aMimeType, aOutputOptions, aStream);
   }
 
   // Use frame 0 from the image container.
-  nsRefPtr<gfxImageSurface> frame;
-  nsresult rv = GetFirstImageFrame(aContainer, getter_AddRefs(frame));
-  NS_ENSURE_SUCCESS(rv, rv);
+  RefPtr<SourceSurface> frame = GetFirstImageFrame(aContainer);
+  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
 
-  int32_t frameWidth = frame->Width(), frameHeight = frame->Height();
+  int32_t frameWidth = frame->GetSize().width;
+  int32_t frameHeight = frame->GetSize().height;
 
   // If the given width or height is zero we'll replace it with the image's
   // original dimensions.
   if (aWidth == 0) {
     aWidth = frameWidth;
   } else if (aHeight == 0) {
     aHeight = frameHeight;
   }
 
   // Check that the given crop rectangle is within image bounds.
   NS_ENSURE_ARG(frameWidth >= aOffsetX + aWidth &&
                 frameHeight >= aOffsetY + aHeight);
 
-  // Create a temporary image surface
-  nsRefPtr<gfxImageSurface> dest = new gfxImageSurface(gfxIntSize(aWidth, aHeight),
-                                                       gfxImageFormat::ARGB32);
-  gfxContext ctx(dest);
-
-  // Set translate
-  ctx.Translate(gfxPoint(-aOffsetX, -aOffsetY));
-
-  // Paint a scaled image
-  ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
-  ctx.SetSource(frame);
-  ctx.Paint();
-
-  return EncodeImageData(dest, aMimeType, aOutputOptions, aStream);
-}
-
-NS_IMETHODIMP imgTools::EncodeImageData(gfxImageSurface *aSurface,
-                                        const nsACString& aMimeType,
-                                        const nsAString& aOutputOptions,
-                                        nsIInputStream **aStream)
-{
-  uint8_t *bitmapData;
-  uint32_t bitmapDataLength, strideSize;
-
-  // Get an image encoder for the media type
-  nsAutoCString encoderCID(
-    NS_LITERAL_CSTRING("@mozilla.org/image/encoder;2?type=") + aMimeType);
-
-  nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(encoderCID.get());
-  if (!encoder)
-    return NS_IMAGELIB_ERROR_NO_ENCODER;
-
-  bitmapData = aSurface->Data();
-  if (!bitmapData)
+  RefPtr<DataSourceSurface> dataSurface =
+    Factory::CreateDataSourceSurface(IntSize(aWidth, aHeight),
+                                     SurfaceFormat::B8G8R8A8);
+  DataSourceSurface::MappedSurface map;
+  dataSurface->Map(DataSourceSurface::MapType::WRITE, &map);
+  if (!map.mData)
     return NS_ERROR_FAILURE;
 
-  strideSize = aSurface->Stride();
-
-  int32_t width = aSurface->Width(), height = aSurface->Height();
-  bitmapDataLength = height * strideSize;
-
-  // Encode the bitmap
-  nsresult rv = encoder->InitFromData(bitmapData,
-                                      bitmapDataLength,
-                                      width,
-                                      height,
-                                      strideSize,
-                                      imgIEncoder::INPUT_FORMAT_HOSTARGB,
-                                      aOutputOptions);
-
-  NS_ENSURE_SUCCESS(rv, rv);
+  RefPtr<DrawTarget> dt =
+    Factory::CreateDrawTargetForData(BackendType::CAIRO,
+                                     map.mData,
+                                     dataSurface->GetSize(),
+                                     map.mStride,
+                                     SurfaceFormat::B8G8R8A8);
+  dt->CopySurface(frame,
+                  IntRect(aOffsetX, aOffsetY, aWidth, aHeight),
+                  IntPoint(0, 0));
 
-  return CallQueryInterface(encoder, aStream);
-}
-
-NS_IMETHODIMP imgTools::GetFirstImageFrame(imgIContainer *aContainer,
-                                           gfxImageSurface **aSurface)
-{
-  nsRefPtr<gfxASurface> surface =
-    aContainer->GetFrame(imgIContainer::FRAME_FIRST,
-                         imgIContainer::FLAG_SYNC_DECODE);
-  NS_ENSURE_TRUE(surface, NS_ERROR_NOT_AVAILABLE);
-
-  nsRefPtr<gfxImageSurface> frame(surface->CopyToARGB32ImageSurface());
-  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
-  NS_ENSURE_TRUE(frame->Width() && frame->Height(), NS_ERROR_FAILURE);
-
-  frame.forget(aSurface);
-  return NS_OK;
+  return EncodeImageData(dataSurface, aMimeType, aOutputOptions, aStream);
 }
 
 NS_IMETHODIMP imgTools::CreateScriptedObserver(imgIScriptedNotificationObserver* aInner,
                                                imgINotificationObserver** aObserver)
 {
   NS_ADDREF(*aObserver = new ScriptedNotificationObserver(aInner));
   return NS_OK;
 }
--- a/image/src/imgTools.h
+++ b/image/src/imgTools.h
@@ -1,36 +1,25 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "imgITools.h"
 
-class gfxImageSurface;
-
 #define NS_IMGTOOLS_CID \
-{ /* 4c2383a4-931c-484d-8c4a-973590f66e3f */         \
-     0x4c2383a4,                                     \
-     0x931c,                                         \
-     0x484d,                                         \
-    {0x8c, 0x4a, 0x97, 0x35, 0x90, 0xf6, 0x6e, 0x3f} \
+{ /* 3d8fa16d-c9e1-4b50-bdef-2c7ae249967a */         \
+     0x3d8fa16d,                                     \
+     0xc9e1,                                         \
+     0x4b50,                                         \
+    {0xbd, 0xef, 0x2c, 0x7a, 0xe2, 0x49, 0x96, 0x7a} \
 }
 
 class imgTools : public imgITools
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_IMGITOOLS
 
   imgTools();
   virtual ~imgTools();
-
-private:
-  NS_IMETHODIMP EncodeImageData(gfxImageSurface *aSurface,
-                                const nsACString& aMimeType,
-                                const nsAString& aOutputOptions,
-                                nsIInputStream **aStream);
-
-  NS_IMETHODIMP GetFirstImageFrame(imgIContainer *aContainer,
-                                   gfxImageSurface **aSurface);
 };