Bug 979853 - Convert the Windows widget consumers of imgIContainer::GetFrame to act on a Moz2D SourceSurface instead of a Thebes gfxASurface. r=mattwoodrow
☠☠ backed out by 7286dfee3104 ☠ ☠
authorJonathan Watt <jwatt@jwatt.org>
Thu, 06 Mar 2014 11:00:31 +0000
changeset 172311 22e34e33e9eec059b1f1c4999e2fb399c9e1ab20
parent 172310 4c9d799155d2461f1362f5c488bc299a77c43e94
child 172312 63a4ad62401ab5b08174e86b80d22b7bdffdc0c9
push id26358
push usercbook@mozilla.com
push dateFri, 07 Mar 2014 11:48:31 +0000
treeherdermozilla-central@b9fc2eb18bd1 [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
widget/windows/nsImageClipboard.cpp
widget/windows/nsWindowGfx.cpp
--- 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,109 @@ 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).
+    data = autoDeleteArray = SurfaceToPackedBGRA(dataSurface);
+    if (!data) {
+      dataSurface->Unmap();
+      return NS_ERROR_FAILURE;
+    }
+  }
+
+  HBITMAP bmp = DataToBitmap(data, iconSize.width, -iconSize.height, 32);
+  uint8_t* a1data = Data32BitTo1Bit(data, iconSize.width, iconSize.height);
+  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;