From c0fabb967ba68129adb1f04b0d6e784132a3a5b5 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Thu, 6 Mar 2014 11:00:31 +0000 Subject: [PATCH] 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 | 41 ++++++--- widget/windows/nsWindowGfx.cpp | 128 +++++++++++++++++++--------- 2 files changed, 117 insertions(+), 52 deletions(-) diff --git a/widget/windows/nsImageClipboard.cpp b/widget/windows/nsImageClipboard.cpp index e2070930c14f..0b6999c125ed 100644 --- a/widget/windows/nsImageClipboard.cpp +++ b/widget/windows/nsImageClipboard.cpp @@ -3,7 +3,8 @@ * 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" @@ -15,6 +16,9 @@ #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? @@ -116,13 +120,23 @@ nsImageToClipboard::CreateFromImage ( imgIContainer* inImage, HANDLE* outBitmap nsresult rv; *outBitmap = nullptr; - nsRefPtr surface = + nsRefPtr 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 frame(surface->GetAsReadableARGB32ImageSurface()); - NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE); + nsRefPtr thebesImageSurface = + thebesSurface->GetAsReadableARGB32ImageSurface(); + NS_ENSURE_TRUE(thebesImageSurface, NS_ERROR_FAILURE); + + IntSize surfaceSize(thebesImageSurface->GetSize().width, + thebesImageSurface->GetSize().height); + RefPtr dataSurface = + Factory::CreateWrappingDataSourceSurface(thebesImageSurface->Data(), + thebesImageSurface->Stride(), + surfaceSize, + SurfaceFormat::B8G8R8A8); + NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE); nsCOMPtr encoder = do_CreateInstance("@mozilla.org/image/encoder;2?type=image/bmp", &rv); NS_ENSURE_SUCCESS(rv, rv); @@ -134,12 +148,12 @@ nsImageToClipboard::CreateFromImage ( imgIContainer* inImage, HANDLE* outBitmap } 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; @@ -147,9 +161,16 @@ nsImageToClipboard::CreateFromImage ( imgIContainer* inImage, HANDLE* outBitmap 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; diff --git a/widget/windows/nsWindowGfx.cpp b/widget/windows/nsWindowGfx.cpp index 4579f52d9efb..9c3442c284a6 100644 --- a/widget/windows/nsWindowGfx.cpp +++ b/widget/windows/nsWindowGfx.cpp @@ -29,6 +29,10 @@ using mozilla::plugins::PluginInstanceParent; #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" @@ -56,6 +60,7 @@ extern "C" { } using namespace mozilla; +using namespace mozilla::gfx; using namespace mozilla::layers; using namespace mozilla::widget; @@ -619,60 +624,99 @@ nsresult nsWindowGfx::CreateIcon(imgIContainer *aContainer, gfxIntSize aScaledSize, HICON *aIcon) { + MOZ_ASSERT((aScaledSize.width > 0 && aScaledSize.height > 0) || + (aScaledSize.width == 0 && aScaledSize.height == 0)); + // Get the image data - nsRefPtr surface = + nsRefPtr 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 frame(surface->GetAsReadableARGB32ImageSurface()); - NS_ENSURE_TRUE(frame, NS_ERROR_NOT_AVAILABLE); + RefPtr 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 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; } - HBITMAP bmp = DataToBitmap(data, width, -height, 32); - uint8_t* a1data = Data32BitTo1Bit(data, width, height); + IntSize iconSize(aScaledSize.width, aScaledSize.height); + if (iconSize == IntSize(0, 0)) { // use frame's intrinsic size + iconSize = surfaceSize; + } + + RefPtr 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 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 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 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};