diff --git a/content/canvas/src/WebGLContext.cpp b/content/canvas/src/WebGLContext.cpp index 99c87398d733..628c8d71cd31 100644 --- a/content/canvas/src/WebGLContext.cpp +++ b/content/canvas/src/WebGLContext.cpp @@ -1371,7 +1371,7 @@ WebGLContext::GetSurfaceSnapshot(bool* aPremultAlpha) if (aPremultAlpha) { *aPremultAlpha = false; } else { - gfxUtils::PremultiplyDataSurface(surf, surf); + gfxUtils::PremultiplyDataSurface(surf); } } diff --git a/content/canvas/src/WebGLContextGL.cpp b/content/canvas/src/WebGLContextGL.cpp index e418ea7835dd..3c510f67021a 100644 --- a/content/canvas/src/WebGLContextGL.cpp +++ b/content/canvas/src/WebGLContextGL.cpp @@ -2530,17 +2530,7 @@ WebGLContext::SurfaceFromElementResultToImageSurface(nsLayoutUtils::SurfaceFromE } if (!mPixelStorePremultiplyAlpha && res.mIsPremultiplied) { - switch (data->GetFormat()) { - case SurfaceFormat::B8G8R8X8: - // No alpha, so de-facto premult'd. - break; - case SurfaceFormat::B8G8R8A8: - data = gfxUtils::CreateUnpremultipliedDataSurface(data); - break; - default: - MOZ_ASSERT(false, "Format unsupported."); - break; - } + data = gfxUtils::UnpremultiplyDataSurface(data); } // We disallow loading cross-domain images and videos that have not been validated diff --git a/gfx/layers/CopyableCanvasLayer.cpp b/gfx/layers/CopyableCanvasLayer.cpp index 381e93e811ec..dd66a7506dea 100644 --- a/gfx/layers/CopyableCanvasLayer.cpp +++ b/gfx/layers/CopyableCanvasLayer.cpp @@ -127,7 +127,7 @@ CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget) Factory::CreateWrappingDataSourceSurface(destData, destStride, destSize, destFormat); mGLContext->Screen()->Readback(sharedSurf, data); if (needsPremult) { - gfxUtils::PremultiplyDataSurface(data, data); + gfxUtils::PremultiplyDataSurface(data); } aDestTarget->ReleaseBits(destData); return; @@ -145,7 +145,7 @@ CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget) // Readback handles Flush/MarkDirty. mGLContext->Screen()->Readback(sharedSurf, data); if (needsPremult) { - gfxUtils::PremultiplyDataSurface(data, data); + gfxUtils::PremultiplyDataSurface(data); } resultSurf = data; } diff --git a/gfx/layers/Effects.h b/gfx/layers/Effects.h index c8147203daac..9742c36dae09 100644 --- a/gfx/layers/Effects.h +++ b/gfx/layers/Effects.h @@ -72,7 +72,7 @@ struct TexturedEffect : public Effect gfx::Rect mTextureCoords; TextureSource* mTexture; bool mPremultiplied; - gfx::Filter mFilter; + gfx::Filter mFilter;; }; // Support an alpha mask. diff --git a/gfx/thebes/gfxUtils.cpp b/gfx/thebes/gfxUtils.cpp index 8253927d3705..da0c010f02b7 100644 --- a/gfx/thebes/gfxUtils.cpp +++ b/gfx/thebes/gfxUtils.cpp @@ -35,270 +35,110 @@ static const uint8_t UnpremultiplyValue(uint8_t a, uint8_t v) { return gfxUtils::sUnpremultiplyTable[a*256+v]; } -static void -PremultiplyData(const uint8_t* srcData, - size_t srcStride, // row-to-row stride in bytes - uint8_t* destData, - size_t destStride, // row-to-row stride in bytes - size_t pixelWidth, - size_t rowCount) +void +gfxUtils::PremultiplyDataSurface(DataSourceSurface *aSurface) { - MOZ_ASSERT(srcData && destData); + // Only premultiply ARGB32 + if (aSurface->GetFormat() != SurfaceFormat::B8G8R8A8) { + return; + } - for (size_t y = 0; y < rowCount; ++y) { - const uint8_t* src = srcData + y * srcStride; - uint8_t* dest = destData + y * destStride; + 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"); - for (size_t x = 0; x < pixelWidth; ++x) { + 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++; + uint8_t b = *src++; + uint8_t g = *src++; + uint8_t r = *src++; + uint8_t a = *src++; - *dest++ = PremultiplyValue(a, b); - *dest++ = PremultiplyValue(a, g); - *dest++ = PremultiplyValue(a, r); - *dest++ = a; + *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++; + uint8_t a = *src++; + uint8_t r = *src++; + uint8_t g = *src++; + uint8_t b = *src++; - *dest++ = a; - *dest++ = PremultiplyValue(a, r); - *dest++ = PremultiplyValue(a, g); - *dest++ = PremultiplyValue(a, b); + *dst++ = a; + *dst++ = PremultiplyValue(a, r); + *dst++ = PremultiplyValue(a, g); + *dst++ = PremultiplyValue(a, b); #endif - } - } -} -static void -UnpremultiplyData(const uint8_t* srcData, - size_t srcStride, // row-to-row stride in bytes - uint8_t* destData, - size_t destStride, // row-to-row stride in bytes - size_t pixelWidth, - size_t rowCount) -{ - MOZ_ASSERT(srcData && destData); - - for (size_t y = 0; y < rowCount; ++y) { - const uint8_t* src = srcData + y * srcStride; - uint8_t* dest = destData + y * destStride; - - for (size_t x = 0; x < pixelWidth; ++x) { -#ifdef IS_LITTLE_ENDIAN - uint8_t b = *src++; - uint8_t g = *src++; - uint8_t r = *src++; - uint8_t a = *src++; - - *dest++ = UnpremultiplyValue(a, b); - *dest++ = UnpremultiplyValue(a, g); - *dest++ = UnpremultiplyValue(a, r); - *dest++ = a; -#else - uint8_t a = *src++; - uint8_t r = *src++; - uint8_t g = *src++; - uint8_t b = *src++; - - *dest++ = a; - *dest++ = UnpremultiplyValue(a, r); - *dest++ = UnpremultiplyValue(a, g); - *dest++ = UnpremultiplyValue(a, b); -#endif - } - } -} - -static bool -MapSrcDest(DataSourceSurface* srcSurf, - DataSourceSurface* destSurf, - DataSourceSurface::MappedSurface* out_srcMap, - DataSourceSurface::MappedSurface* out_destMap) -{ - MOZ_ASSERT(srcSurf && destSurf); - MOZ_ASSERT(out_srcMap && out_destMap); - - if (srcSurf->GetFormat() != SurfaceFormat::B8G8R8A8 || - destSurf->GetFormat() != SurfaceFormat::B8G8R8A8) - { - MOZ_ASSERT(false, "Only operate on BGRA8 surfs."); - return false; } - if (srcSurf->GetSize().width != destSurf->GetSize().width || - srcSurf->GetSize().height != destSurf->GetSize().height) - { - MOZ_ASSERT(false, "Width and height must match."); - return false; - } - - if (srcSurf == destSurf) { - DataSourceSurface::MappedSurface map; - if (!srcSurf->Map(DataSourceSurface::MapType::READ_WRITE, &map)) { - NS_WARNING("Couldn't Map srcSurf/destSurf."); - return false; - } - - *out_srcMap = map; - *out_destMap = map; - return true; - } - - // Map src for reading. - DataSourceSurface::MappedSurface srcMap; - if (!srcSurf->Map(DataSourceSurface::MapType::READ, &srcMap)) { - NS_WARNING("Couldn't Map srcSurf."); - return false; - } - - // Map dest for writing. - DataSourceSurface::MappedSurface destMap; - if (!destSurf->Map(DataSourceSurface::MapType::WRITE, &destMap)) { - NS_WARNING("Couldn't Map aDest."); - srcSurf->Unmap(); - return false; - } - - *out_srcMap = srcMap; - *out_destMap = destMap; - return true; -} - -static void -UnmapSrcDest(DataSourceSurface* srcSurf, - DataSourceSurface* destSurf) -{ - if (srcSurf == destSurf) { - srcSurf->Unmap(); - } else { - srcSurf->Unmap(); - destSurf->Unmap(); - } -} - -bool -gfxUtils::PremultiplyDataSurface(DataSourceSurface* srcSurf, - DataSourceSurface* destSurf) -{ - MOZ_ASSERT(srcSurf && destSurf); - - DataSourceSurface::MappedSurface srcMap; - DataSourceSurface::MappedSurface destMap; - if (!MapSrcDest(srcSurf, destSurf, &srcMap, &destMap)) - return false; - - PremultiplyData(srcMap.mData, srcMap.mStride, - destMap.mData, destMap.mStride, - srcSurf->GetSize().width, - srcSurf->GetSize().height); - - UnmapSrcDest(srcSurf, destSurf); - return true; -} - -bool -gfxUtils::UnpremultiplyDataSurface(DataSourceSurface* srcSurf, - DataSourceSurface* destSurf) -{ - MOZ_ASSERT(srcSurf && destSurf); - - DataSourceSurface::MappedSurface srcMap; - DataSourceSurface::MappedSurface destMap; - if (!MapSrcDest(srcSurf, destSurf, &srcMap, &destMap)) - return false; - - UnpremultiplyData(srcMap.mData, srcMap.mStride, - destMap.mData, destMap.mStride, - srcSurf->GetSize().width, - srcSurf->GetSize().height); - - UnmapSrcDest(srcSurf, destSurf); - return true; -} - -static bool -MapSrcAndCreateMappedDest(DataSourceSurface* srcSurf, - RefPtr* out_destSurf, - DataSourceSurface::MappedSurface* out_srcMap, - DataSourceSurface::MappedSurface* out_destMap) -{ - MOZ_ASSERT(srcSurf); - MOZ_ASSERT(out_destSurf && out_srcMap && out_destMap); - - if (srcSurf->GetFormat() != SurfaceFormat::B8G8R8A8) { - MOZ_ASSERT(false, "Only operate on BGRA8."); - return false; - } - - // Ok, map source for reading. - DataSourceSurface::MappedSurface srcMap; - if (!srcSurf->Map(DataSourceSurface::MapType::READ, &srcMap)) { - MOZ_ASSERT(false, "Couldn't Map srcSurf."); - return false; - } - - // Make our dest surface based on the src. - RefPtr destSurf = - Factory::CreateDataSourceSurfaceWithStride(srcSurf->GetSize(), - srcSurf->GetFormat(), - srcMap.mStride); - - DataSourceSurface::MappedSurface destMap; - if (!destSurf->Map(DataSourceSurface::MapType::WRITE, &destMap)) { - MOZ_ASSERT(false, "Couldn't Map destSurf."); - srcSurf->Unmap(); - return false; - } - - *out_destSurf = destSurf; - *out_srcMap = srcMap; - *out_destMap = destMap; - return true; + aSurface->Unmap(); } TemporaryRef -gfxUtils::CreatePremultipliedDataSurface(DataSourceSurface* srcSurf) +gfxUtils::UnpremultiplyDataSurface(DataSourceSurface* aSurface) { - RefPtr destSurf; - DataSourceSurface::MappedSurface srcMap; - DataSourceSurface::MappedSurface destMap; - if (!MapSrcAndCreateMappedDest(srcSurf, &destSurf, &srcMap, &destMap)) { - MOZ_ASSERT(false, "MapSrcAndCreateMappedDest failed."); - return srcSurf; + // Only premultiply ARGB32 + if (aSurface->GetFormat() != SurfaceFormat::B8G8R8A8) { + return aSurface; } - PremultiplyData(srcMap.mData, srcMap.mStride, - destMap.mData, destMap.mStride, - srcSurf->GetSize().width, - srcSurf->GetSize().height); - - UnmapSrcDest(srcSurf, destSurf); - return destSurf; -} - -TemporaryRef -gfxUtils::CreateUnpremultipliedDataSurface(DataSourceSurface* srcSurf) -{ - RefPtr destSurf; - DataSourceSurface::MappedSurface srcMap; - DataSourceSurface::MappedSurface destMap; - if (!MapSrcAndCreateMappedDest(srcSurf, &destSurf, &srcMap, &destMap)) { - MOZ_ASSERT(false, "MapSrcAndCreateMappedDest failed."); - return srcSurf; + DataSourceSurface::MappedSurface map; + if (!aSurface->Map(DataSourceSurface::MapType::READ, &map)) { + return nullptr; } - UnpremultiplyData(srcMap.mData, srcMap.mStride, - destMap.mData, destMap.mStride, - srcSurf->GetSize().width, - srcSurf->GetSize().height); + RefPtr dest = Factory::CreateDataSourceSurfaceWithStride(aSurface->GetSize(), + aSurface->GetFormat(), + map.mStride); - UnmapSrcDest(srcSurf, destSurf); - return destSurf; + DataSourceSurface::MappedSurface destMap; + if (!dest->Map(DataSourceSurface::MapType::WRITE, &destMap)) { + aSurface->Unmap(); + return nullptr; + } + + uint8_t *src = map.mData; + uint8_t *dst = destMap.mData; + + for (int32_t i = 0; i < aSurface->GetSize().height; ++i) { + uint8_t *srcRow = src + (i * map.mStride); + uint8_t *dstRow = dst + (i * destMap.mStride); + + for (int32_t j = 0; j < aSurface->GetSize().width; ++j) { +#ifdef IS_LITTLE_ENDIAN + uint8_t b = *srcRow++; + uint8_t g = *srcRow++; + uint8_t r = *srcRow++; + uint8_t a = *srcRow++; + + *dstRow++ = UnpremultiplyValue(a, b); + *dstRow++ = UnpremultiplyValue(a, g); + *dstRow++ = UnpremultiplyValue(a, r); + *dstRow++ = a; +#else + uint8_t a = *srcRow++; + uint8_t r = *srcRow++; + uint8_t g = *srcRow++; + uint8_t b = *srcRow++; + + *dstRow++ = a; + *dstRow++ = UnpremultiplyValue(a, r); + *dstRow++ = UnpremultiplyValue(a, g); + *dstRow++ = UnpremultiplyValue(a, b); +#endif + } + } + + aSurface->Unmap(); + dest->Unmap(); + return dest; } void diff --git a/gfx/thebes/gfxUtils.h b/gfx/thebes/gfxUtils.h index 5063b7ef597f..d457ef1661bb 100644 --- a/gfx/thebes/gfxUtils.h +++ b/gfx/thebes/gfxUtils.h @@ -40,15 +40,8 @@ public: * If the source is not gfxImageFormat::ARGB32, no operation is performed. If * aDestSurface is given, the data is copied over. */ - static bool PremultiplyDataSurface(DataSourceSurface* srcSurf, - DataSourceSurface* destSurf); - static bool UnpremultiplyDataSurface(DataSourceSurface* srcSurf, - DataSourceSurface* destSurf); - - static mozilla::TemporaryRef - CreatePremultipliedDataSurface(DataSourceSurface* srcSurf); - static mozilla::TemporaryRef - CreateUnpremultipliedDataSurface(DataSourceSurface* srcSurf); + static void PremultiplyDataSurface(DataSourceSurface *aSurface); + static mozilla::TemporaryRef UnpremultiplyDataSurface(DataSourceSurface* aSurface); static void ConvertBGRAtoRGBA(uint8_t* aData, uint32_t aLength);