Bug 979853 - Convert the Windows widget consumers of imgIContainer::GetFrame to act on a Moz2D SourceSurface instead of a Thebes gfxASurface. r=mattwoodrow
authorJonathan Watt <jwatt@jwatt.org>
Thu, 06 Mar 2014 23:31:22 +0000
changeset 189575 4efacf2f947bbabbf26be8f9e37142b7f22614da
parent 189574 217295b8f163e36154eaafe0950d7256d41b9ce5
child 189576 2ac59d28974c553c93eb814b4a9af8c1eb61c255
push id3503
push userraliiev@mozilla.com
push dateMon, 28 Apr 2014 18:51:11 +0000
treeherdermozilla-beta@c95ac01e332e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs979853
milestone30.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 979853 - Convert the Windows widget consumers of imgIContainer::GetFrame to act on a Moz2D SourceSurface instead of a Thebes gfxASurface. r=mattwoodrow
gfx/2d/SourceSurfaceD2D.cpp
widget/windows/nsImageClipboard.cpp
widget/windows/nsWindowGfx.cpp
--- a/gfx/2d/SourceSurfaceD2D.cpp
+++ b/gfx/2d/SourceSurfaceD2D.cpp
@@ -265,16 +265,17 @@ DataSourceSurfaceD2D::Map(MapType aMapTy
   return true;
 }
 
 void
 DataSourceSurfaceD2D::Unmap()
 {
   MOZ_ASSERT(mIsMapped);
 
+  mIsMapped = false;
   mTexture->Unmap(0);
 }
 
 void
 DataSourceSurfaceD2D::EnsureMappedTexture()
 {
   // Do not use GetData() after having used Map!
   MOZ_ASSERT(!mIsMapped);
--- a/widget/windows/nsImageClipboard.cpp
+++ b/widget/windows/nsImageClipboard.cpp
@@ -1,25 +1,29 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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 "mozilla/gfx/2D.h"
+#include "mozilla/RefPtr.h"
 #include "nsITransferable.h"
 #include "nsImageClipboard.h"
 #include "nsGfxCIID.h"
 #include "nsMemory.h"
 #include "prmem.h"
 #include "imgIEncoder.h"
 #include "nsLiteralString.h"
 #include "nsComponentManagerUtils.h"
 
 #define BFH_LENGTH 14
 
+using namespace mozilla;
+using namespace mozilla::gfx;
+
 /* Things To Do 11/8/00
 
 Check image metrics, can we support them? Do we need to?
 Any other render format? HTML?
 
 */
 
 
@@ -111,50 +115,67 @@ nsImageToClipboard::CalcSpanLength(uint3
 // image. 
 //
 nsresult
 nsImageToClipboard::CreateFromImage ( imgIContainer* inImage, HANDLE* outBitmap )
 {
     nsresult rv;
     *outBitmap = nullptr;
 
-    nsRefPtr<gfxASurface> surface =
+    nsRefPtr<gfxASurface> thebesSurface =
       inImage->GetFrame(imgIContainer::FRAME_CURRENT,
                         imgIContainer::FLAG_SYNC_DECODE);
-    NS_ENSURE_TRUE(surface, NS_ERROR_FAILURE);
+    NS_ENSURE_TRUE(thebesSurface, NS_ERROR_FAILURE);
+
+    nsRefPtr<gfxImageSurface> thebesImageSurface =
+      thebesSurface->GetAsReadableARGB32ImageSurface();
+    NS_ENSURE_TRUE(thebesImageSurface, NS_ERROR_FAILURE);
 
-    nsRefPtr<gfxImageSurface> frame(surface->GetAsReadableARGB32ImageSurface());
-    NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
+    IntSize surfaceSize(thebesImageSurface->GetSize().width,
+                        thebesImageSurface->GetSize().height);
+    RefPtr<DataSourceSurface> dataSurface =
+      Factory::CreateWrappingDataSourceSurface(thebesImageSurface->Data(),
+                                               thebesImageSurface->Stride(),
+                                               surfaceSize,
+                                               SurfaceFormat::B8G8R8A8);
+    NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);
 
     nsCOMPtr<imgIEncoder> encoder = do_CreateInstance("@mozilla.org/image/encoder;2?type=image/bmp", &rv);
     NS_ENSURE_SUCCESS(rv, rv);
     
     uint32_t format;
     nsAutoString options;
     if (mWantDIBV5) {
       options.AppendLiteral("version=5;bpp=");
     } else {
       options.AppendLiteral("version=3;bpp=");
     }
-    switch (frame->Format()) {
-    case gfxImageFormat::ARGB32:
+    switch (dataSurface->GetFormat()) {
+    case SurfaceFormat::B8G8R8A8:
         format = imgIEncoder::INPUT_FORMAT_HOSTARGB;
         options.AppendInt(32);
         break;
-    case gfxImageFormat::RGB24:
+    case SurfaceFormat::B8G8R8X8:
         format = imgIEncoder::INPUT_FORMAT_RGB;
         options.AppendInt(24);
         break;
     default:
         return NS_ERROR_INVALID_ARG;  
     }
 
-    rv = encoder->InitFromData(frame->Data(), 0, frame->Width(),
-                               frame->Height(), frame->Stride(),
+    DataSourceSurface::MappedSurface map;
+    bool mappedOK = dataSurface->Map(DataSourceSurface::MapType::READ, &map);
+    NS_ENSURE_TRUE(mappedOK, NS_ERROR_FAILURE);
+
+    rv = encoder->InitFromData(map.mData, 0,
+                               dataSurface->GetSize().width,
+                               dataSurface->GetSize().height,
+                               map.mStride,
                                format, options);
+    dataSurface->Unmap();
     NS_ENSURE_SUCCESS(rv, rv);
 
     uint32_t size;
     encoder->GetImageBufferUsed(&size);
     NS_ENSURE_TRUE(size > BFH_LENGTH, NS_ERROR_FAILURE);
     HGLOBAL glob = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT,
                                  size - BFH_LENGTH);
     if (!glob)
--- a/widget/windows/nsWindowGfx.cpp
+++ b/widget/windows/nsWindowGfx.cpp
@@ -24,16 +24,20 @@
 #include "mozilla/plugins/PluginInstanceParent.h"
 using mozilla::plugins::PluginInstanceParent;
 
 #include "nsWindowGfx.h"
 #include <windows.h>
 #include "gfxImageSurface.h"
 #include "gfxWindowsSurface.h"
 #include "gfxWindowsPlatform.h"
+#include "mozilla/gfx/2D.h"
+#include "mozilla/gfx/DataSurfaceHelpers.h"
+#include "mozilla/gfx/Tools.h"
+#include "mozilla/RefPtr.h"
 #include "nsGfxCIID.h"
 #include "gfxContext.h"
 #include "nsRenderingContext.h"
 #include "prmem.h"
 #include "WinUtils.h"
 #include "nsIWidgetListener.h"
 #include "mozilla/unused.h"
 
@@ -51,16 +55,17 @@ using mozilla::plugins::PluginInstancePa
 #include "mozilla/gfx/2D.h"
 
 extern "C" {
 #define PIXMAN_DONT_DEFINE_STDINT
 #include "pixman.h"
 }
 
 using namespace mozilla;
+using namespace mozilla::gfx;
 using namespace mozilla::layers;
 using namespace mozilla::widget;
 
 /**************************************************************
  **************************************************************
  **
  ** BLOCK: Variables
  **
@@ -614,70 +619,114 @@ gfxIntSize nsWindowGfx::GetIconMetrics(I
 
 nsresult nsWindowGfx::CreateIcon(imgIContainer *aContainer,
                                   bool aIsCursor,
                                   uint32_t aHotspotX,
                                   uint32_t aHotspotY,
                                   gfxIntSize aScaledSize,
                                   HICON *aIcon) {
 
+  MOZ_ASSERT((aScaledSize.width > 0 && aScaledSize.height > 0) ||
+             (aScaledSize.width == 0 && aScaledSize.height == 0));
+
   // Get the image data
-  nsRefPtr<gfxASurface> surface =
+  nsRefPtr<gfxASurface> thebesSurface =
     aContainer->GetFrame(imgIContainer::FRAME_CURRENT,
                          imgIContainer::FLAG_SYNC_DECODE);
-  NS_ENSURE_TRUE(surface, NS_ERROR_NOT_AVAILABLE);
+  NS_ENSURE_TRUE(thebesSurface, NS_ERROR_NOT_AVAILABLE);
 
-  nsRefPtr<gfxImageSurface> frame(surface->GetAsReadableARGB32ImageSurface());
-  NS_ENSURE_TRUE(frame, NS_ERROR_NOT_AVAILABLE);
+  RefPtr<SourceSurface> surface =
+    gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(nullptr,
+                                                           thebesSurface);
+  NS_ENSURE_TRUE(surface, NS_ERROR_FAILURE);
 
-  int32_t width = frame->Width();
-  int32_t height = frame->Height();
-  if (!width || !height)
+  IntSize surfaceSize(surface->GetSize().width, surface->GetSize().height);
+  if (surfaceSize.IsEmpty()) {
     return NS_ERROR_FAILURE;
-
-  uint8_t *data;
-  nsRefPtr<gfxImageSurface> dest;
-
-  if ((aScaledSize.width == 0 && aScaledSize.height == 0) ||
-      (aScaledSize.width == width && aScaledSize.height == height)) {
-    // We're not scaling the image. The data is simply what's in the frame.
-    data = frame->Data();
   }
-  else {
-    NS_ENSURE_ARG(aScaledSize.width > 0);
-    NS_ENSURE_ARG(aScaledSize.height > 0);
-    // Draw a scaled version of the image to a temporary surface
-    dest = new gfxImageSurface(aScaledSize, gfxImageFormat::ARGB32);
-    if (!dest)
-      return NS_ERROR_OUT_OF_MEMORY;
 
-    gfxContext ctx(dest);
-
-    // Set scaling
-    gfxFloat sw = (double) aScaledSize.width / width;
-    gfxFloat sh = (double) aScaledSize.height / height;
-    ctx.Scale(sw, sh);
-
-    // Paint a scaled image
-    ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
-    ctx.SetSource(frame);
-    ctx.Paint();
-
-    data = dest->Data();
-    width = aScaledSize.width;
-    height = aScaledSize.height;
+  IntSize iconSize(aScaledSize.width, aScaledSize.height);
+  if (iconSize == IntSize(0, 0)) { // use frame's intrinsic size
+    iconSize = surfaceSize;
   }
 
-  HBITMAP bmp = DataToBitmap(data, width, -height, 32);
-  uint8_t* a1data = Data32BitTo1Bit(data, width, height);
+  RefPtr<DataSourceSurface> dataSurface;
+  bool mappedOK;
+  DataSourceSurface::MappedSurface map;
+
+  if (iconSize != surfaceSize) {
+    // Scale the surface
+    dataSurface = Factory::CreateDataSourceSurface(iconSize,
+                                                   SurfaceFormat::B8G8R8A8);
+    NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);
+    mappedOK = dataSurface->Map(DataSourceSurface::MapType::READ_WRITE, &map);
+    NS_ENSURE_TRUE(mappedOK, NS_ERROR_FAILURE);
+
+    RefPtr<DrawTarget> dt =
+      Factory::CreateDrawTargetForData(BackendType::CAIRO,
+                                       map.mData,
+                                       dataSurface->GetSize(),
+                                       map.mStride,
+                                       SurfaceFormat::B8G8R8A8);
+    dt->DrawSurface(surface,
+                    Rect(0, 0, iconSize.width, iconSize.height),
+                    Rect(0, 0, surfaceSize.width, surfaceSize.height),
+                    DrawSurfaceOptions(),
+                    DrawOptions(1.0f, CompositionOp::OP_SOURCE));
+  } else if (surface->GetFormat() != SurfaceFormat::B8G8R8A8) {
+    // Convert format to SurfaceFormat::B8G8R8A8
+    dataSurface = Factory::CreateDataSourceSurface(iconSize,
+                                                   SurfaceFormat::B8G8R8A8);
+    NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);
+
+    RefPtr<DrawTarget> dt =
+      Factory::CreateDrawTargetForData(BackendType::CAIRO,
+                                       map.mData,
+                                       dataSurface->GetSize(),
+                                       map.mStride,
+                                       SurfaceFormat::B8G8R8A8);
+    dt->CopySurface(surface, IntRect(IntPoint(0, 0), iconSize),
+                    IntPoint(0, 0));
+
+    mappedOK = dataSurface->Map(DataSourceSurface::MapType::READ, &map);
+  } else {
+    dataSurface = surface->GetDataSurface();
+    mappedOK = dataSurface->Map(DataSourceSurface::MapType::READ, &map);
+  }
+  NS_ENSURE_TRUE(dataSurface && mappedOK, NS_ERROR_FAILURE);
+  MOZ_ASSERT(dataSurface->GetFormat() == SurfaceFormat::B8G8R8A8);
+
+  uint8_t* data = nullptr;
+  nsAutoArrayPtr<uint8_t> autoDeleteArray;
+  if (map.mStride == BytesPerPixel(dataSurface->GetFormat()) * iconSize.width) {
+    // Mapped data is already packed
+    data = map.mData;
+  } else {
+    // We can't use map.mData since the pixels are not packed (as required by
+    // CreateDIBitmap, which is called under the DataToBitmap call below).
+    //
+    // We must unmap before calling SurfaceToPackedBGRA because it needs access
+    // to the pixel data.
+    dataSurface->Unmap();
+    map.mData = nullptr;
+
+    data = autoDeleteArray = SurfaceToPackedBGRA(dataSurface);
+    NS_ENSURE_TRUE(data, NS_ERROR_FAILURE);
+  }
+
+  HBITMAP bmp = DataToBitmap(data, iconSize.width, -iconSize.height, 32);
+  uint8_t* a1data = Data32BitTo1Bit(data, iconSize.width, iconSize.height);
+  if (map.mData) {
+    dataSurface->Unmap();
+  }
   if (!a1data) {
     return NS_ERROR_FAILURE;
   }
 
-  HBITMAP mbmp = DataToBitmap(a1data, width, -height, 1);
+  HBITMAP mbmp = DataToBitmap(a1data, iconSize.width, -iconSize.height, 1);
   PR_Free(a1data);
 
   ICONINFO info = {0};
   info.fIcon = !aIsCursor;
   info.xHotspot = aHotspotX;
   info.yHotspot = aHotspotY;
   info.hbmMask = mbmp;
   info.hbmColor = bmp;