From f2b9c641927bb658794993678d541d0d178ebca5 Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Tue, 13 May 2014 14:20:26 +1200 Subject: [PATCH] Bug 1006198 - Add PremultiplyDataSurface. r=nical --- gfx/layers/CopyableCanvasLayer.cpp | 6 ++-- gfx/thebes/gfxUtils.cpp | 46 ++++++++++++++++++++++++++++++ gfx/thebes/gfxUtils.h | 1 + 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/gfx/layers/CopyableCanvasLayer.cpp b/gfx/layers/CopyableCanvasLayer.cpp index c3c7c4b4781c..9fe89f487654 100644 --- a/gfx/layers/CopyableCanvasLayer.cpp +++ b/gfx/layers/CopyableCanvasLayer.cpp @@ -21,7 +21,7 @@ #include "nsISupportsImpl.h" // for gfxContext::AddRef, etc #include "nsRect.h" // for nsIntRect #include "nsSize.h" // for nsIntSize -#include "LayerUtils.h" +#include "gfxUtils.h" using namespace mozilla::gfx; using namespace mozilla::gl; @@ -126,7 +126,7 @@ CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget) Factory::CreateWrappingDataSourceSurface(destData, destStride, destSize, destFormat); mGLContext->Screen()->Readback(sharedSurf, data); if (needsPremult) { - PremultiplySurface(data); + gfxUtils::PremultiplyDataSurface(data); } aDestTarget->ReleaseBits(destData); return; @@ -144,7 +144,7 @@ CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget) // Readback handles Flush/MarkDirty. mGLContext->Screen()->Readback(sharedSurf, data); if (needsPremult) { - PremultiplySurface(data); + gfxUtils::PremultiplyDataSurface(data); } resultSurf = data; } diff --git a/gfx/thebes/gfxUtils.cpp b/gfx/thebes/gfxUtils.cpp index 68d30ed2333d..cc9078fbee18 100644 --- a/gfx/thebes/gfxUtils.cpp +++ b/gfx/thebes/gfxUtils.cpp @@ -89,6 +89,52 @@ gfxUtils::PremultiplyImageSurface(gfxImageSurface *aSourceSurface, } } +void +gfxUtils::PremultiplyDataSurface(DataSourceSurface *aSurface) +{ + // Only premultiply ARGB32 + if (aSurface->GetFormat() != SurfaceFormat::B8G8R8A8) { + return; + } + + DataSourceSurface::MappedSurface map; + if (!aSurface->Map(DataSourceSurface::MapType::READ_WRITE, &map)) { + return; + } + MOZ_ASSERT(map.mStride == aSurface->GetSize().width * 4, + "Source surface stride isn't tightly packed"); + + uint8_t *src = map.mData; + uint8_t *dst = map.mData; + + uint32_t dim = aSurface->GetSize().width * aSurface->GetSize().height; + for (uint32_t i = 0; i < dim; ++i) { +#ifdef IS_LITTLE_ENDIAN + uint8_t b = *src++; + uint8_t g = *src++; + uint8_t r = *src++; + uint8_t a = *src++; + + *dst++ = PremultiplyValue(a, b); + *dst++ = PremultiplyValue(a, g); + *dst++ = PremultiplyValue(a, r); + *dst++ = a; +#else + uint8_t a = *src++; + uint8_t r = *src++; + uint8_t g = *src++; + uint8_t b = *src++; + + *dst++ = a; + *dst++ = PremultiplyValue(a, r); + *dst++ = PremultiplyValue(a, g); + *dst++ = PremultiplyValue(a, b); +#endif + } + + aSurface->Unmap(); +} + void gfxUtils::UnpremultiplyImageSurface(gfxImageSurface *aSourceSurface, gfxImageSurface *aDestSurface) diff --git a/gfx/thebes/gfxUtils.h b/gfx/thebes/gfxUtils.h index 3e68d7614c8b..c94fbf3741ed 100644 --- a/gfx/thebes/gfxUtils.h +++ b/gfx/thebes/gfxUtils.h @@ -42,6 +42,7 @@ public: */ static void PremultiplyImageSurface(gfxImageSurface *aSourceSurface, gfxImageSurface *aDestSurface = nullptr); + static void PremultiplyDataSurface(DataSourceSurface *aSurface); static void UnpremultiplyImageSurface(gfxImageSurface *aSurface, gfxImageSurface *aDestSurface = nullptr); static mozilla::TemporaryRef UnpremultiplyDataSurface(DataSourceSurface* aSurface);