diff -r 000000000000 -r 6474c204b198 gfx/layers/LayerUtils.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gfx/layers/LayerUtils.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -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 + } +} + + +} +}