Backed out 6 changesets (bug 1006198) for webgl assertions on a CLOSED TREE

Backed out changeset 5be3c8c44eed (bug 1006198)
Backed out changeset 4b15abd14f28 (bug 1006198)
Backed out changeset bd11a10e7028 (bug 1006198)
Backed out changeset e1044a8ab189 (bug 1006198)
Backed out changeset 558abe22ab30 (bug 1006198)
Backed out changeset 5462b9babaed (bug 1006198)
This commit is contained in:
Wes Kocher 2014-05-12 20:47:52 -07:00
Родитель 6b859b8e96
Коммит a30e4e7afc
10 изменённых файлов: 401 добавлений и 56 удалений

Просмотреть файл

@ -1337,10 +1337,10 @@ WebGLContext::GetSurfaceSnapshot(bool* aPremultAlpha)
if (!gl) if (!gl)
return nullptr; return nullptr;
RefPtr<DataSourceSurface> surf = Factory::CreateDataSourceSurfaceWithStride(IntSize(mWidth, mHeight), nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(gfxIntSize(mWidth, mHeight),
SurfaceFormat::B8G8R8A8, gfxImageFormat::ARGB32,
mWidth * 4); mWidth * 4, 0, false);
if (!surf) { if (surf->CairoStatus() != 0) {
return nullptr; return nullptr;
} }
@ -1348,7 +1348,7 @@ WebGLContext::GetSurfaceSnapshot(bool* aPremultAlpha)
{ {
ScopedBindFramebuffer autoFB(gl, 0); ScopedBindFramebuffer autoFB(gl, 0);
ClearBackbufferIfNeeded(); ClearBackbufferIfNeeded();
ReadPixelsIntoDataSurface(gl, surf); ReadPixelsIntoImageSurface(gl, surf);
} }
if (aPremultAlpha) { if (aPremultAlpha) {
@ -1359,7 +1359,8 @@ WebGLContext::GetSurfaceSnapshot(bool* aPremultAlpha)
if (aPremultAlpha) { if (aPremultAlpha) {
*aPremultAlpha = false; *aPremultAlpha = false;
} else { } else {
gfxUtils::PremultiplyDataSurface(surf); gfxUtils::PremultiplyImageSurface(surf);
surf->MarkDirty();
} }
} }
@ -1372,12 +1373,14 @@ WebGLContext::GetSurfaceSnapshot(bool* aPremultAlpha)
return nullptr; return nullptr;
} }
RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, surf);
Matrix m; Matrix m;
m.Translate(0.0, mHeight); m.Translate(0.0, mHeight);
m.Scale(1.0, -1.0); m.Scale(1.0, -1.0);
dt->SetTransform(m); dt->SetTransform(m);
dt->DrawSurface(surf, dt->DrawSurface(source,
Rect(0, 0, mWidth, mHeight), Rect(0, 0, mWidth, mHeight),
Rect(0, 0, mWidth, mHeight), Rect(0, 0, mWidth, mHeight),
DrawSurfaceOptions(), DrawSurfaceOptions(),

Просмотреть файл

@ -328,40 +328,44 @@ GuessAlignment(int width, int pixelSize, int rowStride)
} }
void void
ReadPixelsIntoDataSurface(GLContext* gl, DataSourceSurface* dest) { ReadPixelsIntoImageSurface(GLContext* gl, gfxImageSurface* dest) {
gl->MakeCurrent(); gl->MakeCurrent();
MOZ_ASSERT(dest->GetSize().width != 0); MOZ_ASSERT(dest->GetSize() != gfxIntSize(0, 0));
MOZ_ASSERT(dest->GetSize().height != 0);
bool hasAlpha = dest->GetFormat() == SurfaceFormat::B8G8R8A8 || /* gfxImageFormat::ARGB32:
dest->GetFormat() == SurfaceFormat::R8G8B8A8; * RGBA+UByte: be[RGBA], le[ABGR]
* RGBA+UInt: be[ABGR], le[RGBA]
* BGRA+UInt: be[ARGB], le[BGRA]
* BGRA+UIntRev: be[BGRA], le[ARGB]
*
* gfxImageFormat::RGB16_565:
* RGB+UShort: le[rrrrrggg,gggbbbbb]
*/
bool hasAlpha = dest->Format() == gfxImageFormat::ARGB32;
int destPixelSize; int destPixelSize;
GLenum destFormat; GLenum destFormat;
GLenum destType; GLenum destType;
switch (dest->GetFormat()) { switch (dest->Format()) {
case SurfaceFormat::B8G8R8A8: case gfxImageFormat::RGB24: // XRGB
case SurfaceFormat::B8G8R8X8: case gfxImageFormat::ARGB32:
destPixelSize = 4;
// Needs host (little) endian ARGB. // Needs host (little) endian ARGB.
destFormat = LOCAL_GL_BGRA; destFormat = LOCAL_GL_BGRA;
destType = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV; destType = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
break; break;
case SurfaceFormat::R8G8B8A8:
case SurfaceFormat::R8G8B8X8: case gfxImageFormat::RGB16_565:
// Needs host (little) endian ABGR. destPixelSize = 2;
destFormat = LOCAL_GL_RGBA;
destType = LOCAL_GL_UNSIGNED_BYTE;
break;
case SurfaceFormat::R5G6B5:
destFormat = LOCAL_GL_RGB; destFormat = LOCAL_GL_RGB;
destType = LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV; destType = LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV;
break; break;
default: default:
MOZ_CRASH("Bad format."); MOZ_CRASH("Bad format.");
} }
destPixelSize = BytesPerPixel(dest->GetFormat()); MOZ_ASSERT(dest->Width() * destPixelSize <= dest->Stride());
MOZ_ASSERT(dest->GetSize().width * destPixelSize <= dest->Stride());
GLenum readFormat = destFormat; GLenum readFormat = destFormat;
GLenum readType = destType; GLenum readType = destType;
@ -369,15 +373,20 @@ ReadPixelsIntoDataSurface(GLContext* gl, DataSourceSurface* dest) {
destFormat, destType, destFormat, destType,
readFormat, readType); readFormat, readType);
RefPtr<DataSourceSurface> tempSurf; nsAutoPtr<gfxImageSurface> tempSurf;
DataSourceSurface* readSurf = dest; gfxImageSurface* readSurf = nullptr;
int readAlignment = GuessAlignment(dest->GetSize().width,
// Figure out alignment. We don't need to know why, we just need it
// to be valid.
int readAlignment = GuessAlignment(dest->Width(),
destPixelSize, destPixelSize,
dest->Stride()); dest->Stride());
if (!readAlignment) { if (!readAlignment) // Couldn't calculate a valid alignment.
needsTempSurf = true; needsTempSurf = true;
}
if (needsTempSurf) { if (!needsTempSurf) {
readSurf = dest;
} else {
if (gl->DebugMode()) { if (gl->DebugMode()) {
NS_WARNING("Needing intermediary surface for ReadPixels. This will be slow!"); NS_WARNING("Needing intermediary surface for ReadPixels. This will be slow!");
} }
@ -422,11 +431,154 @@ ReadPixelsIntoDataSurface(GLContext* gl, DataSourceSurface* dest) {
} }
} }
tempSurf = new gfxImageSurface(dest->GetSize(),
SurfaceFormatToImageFormat(readFormatGFX),
false);
readSurf = tempSurf;
}
MOZ_ASSERT(readAlignment);
GLint currentPackAlignment = 0;
gl->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, &currentPackAlignment);
if (currentPackAlignment != readAlignment)
gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, readAlignment);
GLsizei width = dest->Width();
GLsizei height = dest->Height();
readSurf->Flush();
gl->fReadPixels(0, 0,
width, height,
readFormat, readType,
readSurf->Data());
readSurf->MarkDirty();
if (currentPackAlignment != readAlignment)
gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, currentPackAlignment);
if (readSurf != dest) {
MOZ_ASSERT(readFormat == LOCAL_GL_RGBA);
MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_BYTE);
// So we just copied in RGBA in big endian, or le: 0xAABBGGRR.
// We want 0xAARRGGBB, so swap R and B:
dest->Flush();
RefPtr<DataSourceSurface> readDSurf =
Factory::CreateWrappingDataSourceSurface(readSurf->Data(),
readSurf->Stride(),
ToIntSize(readSurf->GetSize()),
ImageFormatToSurfaceFormat(readSurf->Format()));
SwapRAndBComponents(readDSurf);
dest->MarkDirty();
gfxContext ctx(dest);
ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
ctx.SetSource(readSurf);
ctx.Paint();
}
// Check if GL is giving back 1.0 alpha for
// RGBA reads to RGBA images from no-alpha buffers.
#ifdef XP_MACOSX
if (gl->WorkAroundDriverBugs() &&
gl->Vendor() == gl::GLVendor::NVIDIA &&
dest->Format() == gfxImageFormat::ARGB32 &&
width && height)
{
GLint alphaBits = 0;
gl->fGetIntegerv(LOCAL_GL_ALPHA_BITS, &alphaBits);
if (!alphaBits) {
const uint32_t alphaMask = gfxPackedPixelNoPreMultiply(0xff,0,0,0);
MOZ_ASSERT(dest->Width() * destPixelSize == dest->Stride());
dest->Flush();
uint32_t* itr = (uint32_t*)dest->Data();
uint32_t testPixel = *itr;
if ((testPixel & alphaMask) != alphaMask) {
// We need to set the alpha channel to 1.0 manually.
uint32_t* itrEnd = itr + width*height; // Stride is guaranteed to be width*4.
for (; itr != itrEnd; itr++) {
*itr |= alphaMask;
}
}
dest->MarkDirty();
}
}
#endif
}
void
ReadPixelsIntoDataSurface(GLContext* gl, DataSourceSurface* dest) {
gl->MakeCurrent();
MOZ_ASSERT(dest->GetSize().width != 0);
MOZ_ASSERT(dest->GetSize().height != 0);
bool hasAlpha = dest->GetFormat() == SurfaceFormat::B8G8R8A8 ||
dest->GetFormat() == SurfaceFormat::R8G8B8A8;
int destPixelSize;
GLenum destFormat;
GLenum destType;
switch (dest->GetFormat()) {
case SurfaceFormat::B8G8R8A8:
case SurfaceFormat::B8G8R8X8:
// Needs host (little) endian ARGB.
destFormat = LOCAL_GL_BGRA;
destType = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
break;
case SurfaceFormat::R8G8B8A8:
case SurfaceFormat::R8G8B8X8:
// Needs host (little) endian ABGR.
destFormat = LOCAL_GL_RGBA;
destType = LOCAL_GL_UNSIGNED_BYTE;
break;
case SurfaceFormat::R5G6B5:
destFormat = LOCAL_GL_RGB;
destType = LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV;
break;
default:
MOZ_CRASH("Bad format.");
}
destPixelSize = BytesPerPixel(dest->GetFormat());
MOZ_ASSERT(dest->GetSize().width * destPixelSize <= dest->Stride());
GLenum readFormat = destFormat;
GLenum readType = destType;
bool needsTempSurf = !GetActualReadFormats(gl,
destFormat, destType,
readFormat, readType);
RefPtr<DataSourceSurface> tempSurf;
DataSourceSurface* readSurf = nullptr;
int readAlignment = 0;
if (needsTempSurf) {
if (gl->DebugMode()) {
NS_WARNING("Needing intermediary surface for ReadPixels. This will be slow!");
}
SurfaceFormat readFormatGFX;
// If needs temp surface, readFormat is always LOCAL_GL_RGBA
// and readType is always LOCAL_GL_UNSIGNED_BYTE
MOZ_ASSERT(readFormat == LOCAL_GL_RGBA);
MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_BYTE);
readFormatGFX = hasAlpha ? SurfaceFormat::R8G8B8A8
: SurfaceFormat::R8G8B8X8;
readAlignment = 1;
int32_t stride = dest->GetSize().width * BytesPerPixel(readFormatGFX); int32_t stride = dest->GetSize().width * BytesPerPixel(readFormatGFX);
tempSurf = Factory::CreateDataSourceSurfaceWithStride(dest->GetSize(), tempSurf = Factory::CreateDataSourceSurfaceWithStride(dest->GetSize(),
readFormatGFX, readFormatGFX,
stride); stride);
readSurf = tempSurf; readSurf = tempSurf;
} else {
// Figure out alignment. We don't need to know why, we just need it
// to be valid.
readAlignment = GuessAlignment(dest->GetSize().width,
destPixelSize,
dest->Stride());
readSurf = dest;
} }
MOZ_ASSERT(readAlignment); MOZ_ASSERT(readAlignment);
MOZ_ASSERT(reinterpret_cast<uintptr_t>(readSurf->GetData()) % readAlignment == 0); MOZ_ASSERT(reinterpret_cast<uintptr_t>(readSurf->GetData()) % readAlignment == 0);
@ -553,6 +705,14 @@ ReadBackSurface(GLContext* gl, GLuint aTexture, bool aYInvert, SurfaceFormat aFo
return surf.forget(); return surf.forget();
} }
void
ReadScreenIntoImageSurface(GLContext* gl, gfxImageSurface* dest)
{
ScopedBindFramebuffer autoFB(gl, 0);
ReadPixelsIntoImageSurface(gl, dest);
}
#define CLEANUP_IF_GLERROR_OCCURRED(x) \ #define CLEANUP_IF_GLERROR_OCCURRED(x) \
if (DidGLErrorOccur(x)) { \ if (DidGLErrorOccur(x)) { \
isurf = nullptr; \ isurf = nullptr; \

Просмотреть файл

@ -26,6 +26,8 @@ namespace gl {
void ReadPixelsIntoDataSurface(GLContext* aGL, void ReadPixelsIntoDataSurface(GLContext* aGL,
gfx::DataSourceSurface* aSurface); gfx::DataSourceSurface* aSurface);
void ReadPixelsIntoImageSurface(GLContext* aGL, gfxImageSurface* aSurface);
void ReadScreenIntoImageSurface(GLContext* aGL, gfxImageSurface* aSurface);
TemporaryRef<gfx::DataSourceSurface> TemporaryRef<gfx::DataSourceSurface>
ReadBackSurface(GLContext* gl, GLuint aTexture, bool aYInvert, gfx::SurfaceFormat aFormat); ReadBackSurface(GLContext* gl, GLuint aTexture, bool aYInvert, gfx::SurfaceFormat aFormat);

Просмотреть файл

@ -17,12 +17,11 @@
#include "gfxUtils.h" // for gfxUtils #include "gfxUtils.h" // for gfxUtils
#include "gfx2DGlue.h" // for thebes --> moz2d transition #include "gfx2DGlue.h" // for thebes --> moz2d transition
#include "mozilla/gfx/BaseSize.h" // for BaseSize #include "mozilla/gfx/BaseSize.h" // for BaseSize
#include "mozilla/gfx/Tools.h"
#include "nsDebug.h" // for NS_ASSERTION, NS_WARNING, etc #include "nsDebug.h" // for NS_ASSERTION, NS_WARNING, etc
#include "nsISupportsImpl.h" // for gfxContext::AddRef, etc #include "nsISupportsImpl.h" // for gfxContext::AddRef, etc
#include "nsRect.h" // for nsIntRect #include "nsRect.h" // for nsIntRect
#include "nsSize.h" // for nsIntSize #include "nsSize.h" // for nsIntSize
#include "gfxUtils.h" #include "LayerUtils.h"
using namespace mozilla::gfx; using namespace mozilla::gfx;
using namespace mozilla::gl; using namespace mozilla::gl;
@ -127,7 +126,7 @@ CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget)
Factory::CreateWrappingDataSourceSurface(destData, destStride, destSize, destFormat); Factory::CreateWrappingDataSourceSurface(destData, destStride, destSize, destFormat);
mGLContext->Screen()->Readback(sharedSurf, data); mGLContext->Screen()->Readback(sharedSurf, data);
if (needsPremult) { if (needsPremult) {
gfxUtils::PremultiplyDataSurface(data); PremultiplySurface(data);
} }
aDestTarget->ReleaseBits(destData); aDestTarget->ReleaseBits(destData);
return; return;
@ -145,7 +144,7 @@ CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget)
// Readback handles Flush/MarkDirty. // Readback handles Flush/MarkDirty.
mGLContext->Screen()->Readback(sharedSurf, data); mGLContext->Screen()->Readback(sharedSurf, data);
if (needsPremult) { if (needsPremult) {
gfxUtils::PremultiplyDataSurface(data); PremultiplySurface(data);
} }
resultSurf = data; resultSurf = data;
} }
@ -171,9 +170,7 @@ CopyableCanvasLayer::GetTempSurface(const IntSize& aSize,
aSize != mCachedTempSurface->GetSize() || aSize != mCachedTempSurface->GetSize() ||
aFormat != mCachedTempSurface->GetFormat()) aFormat != mCachedTempSurface->GetFormat())
{ {
// Create a surface aligned to 8 bytes since that's the highest alignment WebGL can handle. mCachedTempSurface = Factory::CreateDataSourceSurface(aSize, aFormat);
uint32_t stride = GetAlignedStride<8>(aSize.width * BytesPerPixel(aFormat));
mCachedTempSurface = Factory::CreateDataSourceSurfaceWithStride(aSize, aFormat, stride);
} }
return mCachedTempSurface; return mCachedTempSurface;

101
gfx/layers/LayerUtils.cpp Normal file
Просмотреть файл

@ -0,0 +1,101 @@
/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "LayerUtils.h"
#include "PremultiplyTables.h"
#include "mozilla/Endian.h"
namespace mozilla {
namespace layers {
using namespace mozilla::gfx;
static inline const uint8_t PremultiplyValue(uint8_t a, uint8_t v) {
return PremultiplyTable[a*256+v];
}
static inline const uint8_t UnpremultiplyValue(uint8_t a, uint8_t v) {
return UnpremultiplyTable[a*256+v];
}
#ifdef DEBUG
static bool IsLittleEndian()
{
// Violate strict aliasing, because violating strict aliasing is how
// we always pack and unpack between uint32_t and uint8_t[].
uint16_t testShort;
static const uint8_t testBytes[2] = { 0xAA, 0xBB };
memcpy(&testShort, testBytes, sizeof(testBytes));
return testShort == 0xBBAA;
}
#endif // DEBUG
#ifdef MOZ_LITTLE_ENDIAN
#define ASSERT_ENDIAN() MOZ_ASSERT(IsLittleEndian(), "Defined as little endian, but actually big!")
#else
#define ASSERT_ENDIAN() MOZ_ASSERT(!IsLittleEndian(), "Defined as big endian, but actually little!")
#endif
void
PremultiplySurface(DataSourceSurface* srcSurface,
DataSourceSurface* destSurface)
{
if (!destSurface)
destSurface = srcSurface;
IntSize srcSize = srcSurface->GetSize();
MOZ_ASSERT(srcSurface->GetFormat() == destSurface->GetFormat() &&
srcSize.width == destSurface->GetSize().width &&
srcSize.height == destSurface->GetSize().height &&
srcSurface->Stride() == destSurface->Stride(),
"Source and destination surfaces don't have identical characteristics");
MOZ_ASSERT(srcSurface->Stride() == srcSize.width * 4,
"Source surface stride isn't tightly packed");
// Only premultiply ARGB32
if (srcSurface->GetFormat() != SurfaceFormat::B8G8R8A8) {
if (destSurface != srcSurface) {
memcpy(destSurface->GetData(), srcSurface->GetData(),
srcSurface->Stride() * srcSize.height);
}
return;
}
uint8_t *src = srcSurface->GetData();
uint8_t *dst = destSurface->GetData();
// Assert that our endian define is correct.
ASSERT_ENDIAN();
uint32_t dim = srcSize.width * srcSize.height;
for (uint32_t i = 0; i < dim; ++i) {
#ifdef MOZ_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
}
}
}
}

21
gfx/layers/LayerUtils.h Normal file
Просмотреть файл

@ -0,0 +1,21 @@
/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef MOZILLA_LAYERS_LAYERUTILS_H_
#define MOZILLA_LAYERS_LAYERUTILS_H_
#include "mozilla/gfx/2D.h"
namespace mozilla {
namespace layers {
void
PremultiplySurface(gfx::DataSourceSurface* srcSurface,
gfx::DataSourceSurface* destSurface = nullptr);
}
}
#endif /* MOZILLA_LAYERS_LAYERUTILS_H_ */

Просмотреть файл

@ -124,10 +124,6 @@ ImageHost::Composite(EffectChain& aEffectChain,
} else { } else {
effect->mTextureCoords = Rect(0, 0, 1, 1); effect->mTextureCoords = Rect(0, 0, 1, 1);
} }
if (mFrontBuffer->GetFlags() & TextureFlags::NEEDS_Y_FLIP) {
effect->mTextureCoords.y = effect->mTextureCoords.YMost();
effect->mTextureCoords.height = -effect->mTextureCoords.height;
}
GetCompositor()->DrawQuad(rect, aClipRect, aEffectChain, GetCompositor()->DrawQuad(rect, aClipRect, aEffectChain,
aOpacity, aTransform); aOpacity, aTransform);
GetCompositor()->DrawDiagnostics(DiagnosticFlags::IMAGE | DiagnosticFlags::BIGIMAGE, GetCompositor()->DrawDiagnostics(DiagnosticFlags::IMAGE | DiagnosticFlags::BIGIMAGE,

Просмотреть файл

@ -294,6 +294,7 @@ UNIFIED_SOURCES += [
'LayerScope.cpp', 'LayerScope.cpp',
'LayersLogging.cpp', 'LayersLogging.cpp',
'LayerSorter.cpp', 'LayerSorter.cpp',
'LayerUtils.cpp',
'opengl/CompositingRenderTargetOGL.cpp', 'opengl/CompositingRenderTargetOGL.cpp',
'opengl/CompositorOGL.cpp', 'opengl/CompositorOGL.cpp',
'opengl/OGLShaderProgram.cpp', 'opengl/OGLShaderProgram.cpp',

Просмотреть файл

@ -36,24 +36,34 @@ static const uint8_t UnpremultiplyValue(uint8_t a, uint8_t v) {
} }
void void
gfxUtils::PremultiplyDataSurface(DataSourceSurface *aSurface) gfxUtils::PremultiplyImageSurface(gfxImageSurface *aSourceSurface,
gfxImageSurface *aDestSurface)
{ {
// Only premultiply ARGB32 if (!aDestSurface)
if (aSurface->GetFormat() != SurfaceFormat::B8G8R8A8) { aDestSurface = aSourceSurface;
return;
}
DataSourceSurface::MappedSurface map; MOZ_ASSERT(aSourceSurface->Format() == aDestSurface->Format() &&
if (!aSurface->Map(DataSourceSurface::MapType::READ_WRITE, &map)) { aSourceSurface->Width() == aDestSurface->Width() &&
return; aSourceSurface->Height() == aDestSurface->Height() &&
} aSourceSurface->Stride() == aDestSurface->Stride(),
MOZ_ASSERT(map.mStride == aSurface->GetSize().width * 4, "Source and destination surfaces don't have identical characteristics");
MOZ_ASSERT(aSourceSurface->Stride() == aSourceSurface->Width() * 4,
"Source surface stride isn't tightly packed"); "Source surface stride isn't tightly packed");
uint8_t *src = map.mData; // Only premultiply ARGB32
uint8_t *dst = map.mData; if (aSourceSurface->Format() != gfxImageFormat::ARGB32) {
if (aDestSurface != aSourceSurface) {
memcpy(aDestSurface->Data(), aSourceSurface->Data(),
aSourceSurface->Stride() * aSourceSurface->Height());
}
return;
}
uint32_t dim = aSurface->GetSize().width * aSurface->GetSize().height; uint8_t *src = aSourceSurface->Data();
uint8_t *dst = aDestSurface->Data();
uint32_t dim = aSourceSurface->Width() * aSourceSurface->Height();
for (uint32_t i = 0; i < dim; ++i) { for (uint32_t i = 0; i < dim; ++i) {
#ifdef IS_LITTLE_ENDIAN #ifdef IS_LITTLE_ENDIAN
uint8_t b = *src++; uint8_t b = *src++;
@ -77,8 +87,59 @@ gfxUtils::PremultiplyDataSurface(DataSourceSurface *aSurface)
*dst++ = PremultiplyValue(a, b); *dst++ = PremultiplyValue(a, b);
#endif #endif
} }
}
aSurface->Unmap(); void
gfxUtils::UnpremultiplyImageSurface(gfxImageSurface *aSourceSurface,
gfxImageSurface *aDestSurface)
{
if (!aDestSurface)
aDestSurface = aSourceSurface;
MOZ_ASSERT(aSourceSurface->Format() == aDestSurface->Format() &&
aSourceSurface->Width() == aDestSurface->Width() &&
aSourceSurface->Height() == aDestSurface->Height(),
"Source and destination surfaces don't have identical characteristics");
// Only premultiply ARGB32
if (aSourceSurface->Format() != gfxImageFormat::ARGB32) {
if (aDestSurface != aSourceSurface) {
aDestSurface->CopyFrom(aSourceSurface);
}
return;
}
uint8_t *src = aSourceSurface->Data();
uint8_t *dst = aDestSurface->Data();
for (int32_t i = 0; i < aSourceSurface->Height(); ++i) {
uint8_t *srcRow = src + (i * aSourceSurface->Stride());
uint8_t *dstRow = dst + (i * aDestSurface->Stride());
for (int32_t j = 0; j < aSourceSurface->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
}
}
} }
TemporaryRef<DataSourceSurface> TemporaryRef<DataSourceSurface>

Просмотреть файл

@ -40,7 +40,10 @@ public:
* If the source is not gfxImageFormat::ARGB32, no operation is performed. If * If the source is not gfxImageFormat::ARGB32, no operation is performed. If
* aDestSurface is given, the data is copied over. * aDestSurface is given, the data is copied over.
*/ */
static void PremultiplyDataSurface(DataSourceSurface *aSurface); static void PremultiplyImageSurface(gfxImageSurface *aSourceSurface,
gfxImageSurface *aDestSurface = nullptr);
static void UnpremultiplyImageSurface(gfxImageSurface *aSurface,
gfxImageSurface *aDestSurface = nullptr);
static mozilla::TemporaryRef<DataSourceSurface> UnpremultiplyDataSurface(DataSourceSurface* aSurface); static mozilla::TemporaryRef<DataSourceSurface> UnpremultiplyDataSurface(DataSourceSurface* aSurface);
static void ConvertBGRAtoRGBA(gfxImageSurface *aSourceSurface, static void ConvertBGRAtoRGBA(gfxImageSurface *aSourceSurface,