Bug 1006198 - Add PremultiplyDataSurface. r=nical
authorMatt Woodrow <mwoodrow@mozilla.com>
Tue, 13 May 2014 14:20:26 +1200
changeset 182818 d60356c63c4fd7563361aff218bd5d2d2f7543a8
parent 182817 98a354e678c2ae67b5f1284ba8380d60be5d9a15
child 182819 0675a2349cfce3b1df9602a1ce25ff1ff64f5132
push id43403
push usermwoodrow@mozilla.com
push dateTue, 13 May 2014 09:12:47 +0000
treeherdermozilla-inbound@0ff7d00bb9fb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnical
bugs1006198
milestone32.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 1006198 - Add PremultiplyDataSurface. r=nical
gfx/layers/CopyableCanvasLayer.cpp
gfx/thebes/gfxUtils.cpp
gfx/thebes/gfxUtils.h
--- a/gfx/layers/CopyableCanvasLayer.cpp
+++ b/gfx/layers/CopyableCanvasLayer.cpp
@@ -16,17 +16,17 @@
 #include "gfxRect.h"                    // for gfxRect
 #include "gfxUtils.h"                   // for gfxUtils
 #include "gfx2DGlue.h"                  // for thebes --> moz2d transition
 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
 #include "nsDebug.h"                    // for NS_ASSERTION, NS_WARNING, etc
 #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;
 
 namespace mozilla {
 namespace layers {
 
 CopyableCanvasLayer::CopyableCanvasLayer(LayerManager* aLayerManager, void *aImplData) :
@@ -121,17 +121,17 @@ CopyableCanvasLayer::UpdateTarget(DrawTa
       int32_t destStride;
       SurfaceFormat destFormat;
       if (aDestTarget->LockBits(&destData, &destSize, &destStride, &destFormat)) {
         if (destSize == readSize && destFormat == format) {
           RefPtr<DataSourceSurface> data =
             Factory::CreateWrappingDataSourceSurface(destData, destStride, destSize, destFormat);
           mGLContext->Screen()->Readback(sharedSurf, data);
           if (needsPremult) {
-            PremultiplySurface(data);
+              gfxUtils::PremultiplyDataSurface(data);
           }
           aDestTarget->ReleaseBits(destData);
           return;
         }
         aDestTarget->ReleaseBits(destData);
       }
     }
 
@@ -139,17 +139,17 @@ CopyableCanvasLayer::UpdateTarget(DrawTa
     if (sharedSurf->Type() == SharedSurfaceType::Basic && !needsPremult) {
       SharedSurface_Basic* sharedSurf_Basic = SharedSurface_Basic::Cast(sharedSurf);
       resultSurf = sharedSurf_Basic->GetData();
     } else {
       RefPtr<DataSourceSurface> data = GetTempSurface(readSize, format);
       // Readback handles Flush/MarkDirty.
       mGLContext->Screen()->Readback(sharedSurf, data);
       if (needsPremult) {
-        PremultiplySurface(data);
+        gfxUtils::PremultiplyDataSurface(data);
       }
       resultSurf = data;
     }
     MOZ_ASSERT(resultSurf);
 
     if (aDestTarget) {
       aDestTarget->CopySurface(resultSurf,
                                IntRect(0, 0, readSize.width, readSize.height),
--- a/gfx/thebes/gfxUtils.cpp
+++ b/gfx/thebes/gfxUtils.cpp
@@ -85,16 +85,62 @@ gfxUtils::PremultiplyImageSurface(gfxIma
         *dst++ = PremultiplyValue(a, r);
         *dst++ = PremultiplyValue(a, g);
         *dst++ = PremultiplyValue(a, b);
 #endif
     }
 }
 
 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)
 {
     if (!aDestSurface)
         aDestSurface = aSourceSurface;
 
     MOZ_ASSERT(aSourceSurface->Format() == aDestSurface->Format() &&
                aSourceSurface->Width()  == aDestSurface->Width() &&
--- a/gfx/thebes/gfxUtils.h
+++ b/gfx/thebes/gfxUtils.h
@@ -37,16 +37,17 @@ public:
      * If aDestSurface is given, it must have identical format, dimensions, and
      * stride as the source.
      *
      * If the source is not gfxImageFormat::ARGB32, no operation is performed.  If
      * aDestSurface is given, the data is copied over.
      */
     static void PremultiplyImageSurface(gfxImageSurface *aSourceSurface,
                                         gfxImageSurface *aDestSurface = nullptr);
+    static void PremultiplyDataSurface(DataSourceSurface *aSurface);
     static void UnpremultiplyImageSurface(gfxImageSurface *aSurface,
                                           gfxImageSurface *aDestSurface = nullptr);
     static mozilla::TemporaryRef<DataSourceSurface> UnpremultiplyDataSurface(DataSourceSurface* aSurface);
 
     static void ConvertBGRAtoRGBA(gfxImageSurface *aSourceSurface,
                                   gfxImageSurface *aDestSurface = nullptr);
     static void ConvertBGRAtoRGBA(uint8_t* aData, uint32_t aLength);