michael@0: /* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "LayerUtils.h" michael@0: #include "PremultiplyTables.h" michael@0: #include "mozilla/Endian.h" michael@0: michael@0: namespace mozilla { michael@0: namespace layers { michael@0: michael@0: using namespace mozilla::gfx; michael@0: michael@0: static inline const uint8_t PremultiplyValue(uint8_t a, uint8_t v) { michael@0: return PremultiplyTable[a*256+v]; michael@0: } michael@0: michael@0: static inline const uint8_t UnpremultiplyValue(uint8_t a, uint8_t v) { michael@0: return UnpremultiplyTable[a*256+v]; michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: static bool IsLittleEndian() michael@0: { michael@0: // Violate strict aliasing, because violating strict aliasing is how michael@0: // we always pack and unpack between uint32_t and uint8_t[]. michael@0: uint16_t testShort; michael@0: static const uint8_t testBytes[2] = { 0xAA, 0xBB }; michael@0: memcpy(&testShort, testBytes, sizeof(testBytes)); michael@0: return testShort == 0xBBAA; michael@0: } michael@0: #endif // DEBUG michael@0: michael@0: #ifdef MOZ_LITTLE_ENDIAN michael@0: #define ASSERT_ENDIAN() MOZ_ASSERT(IsLittleEndian(), "Defined as little endian, but actually big!") michael@0: #else michael@0: #define ASSERT_ENDIAN() MOZ_ASSERT(!IsLittleEndian(), "Defined as big endian, but actually little!") michael@0: #endif michael@0: michael@0: void michael@0: PremultiplySurface(DataSourceSurface* srcSurface, michael@0: DataSourceSurface* destSurface) michael@0: { michael@0: if (!destSurface) michael@0: destSurface = srcSurface; michael@0: michael@0: IntSize srcSize = srcSurface->GetSize(); michael@0: MOZ_ASSERT(srcSurface->GetFormat() == destSurface->GetFormat() && michael@0: srcSize.width == destSurface->GetSize().width && michael@0: srcSize.height == destSurface->GetSize().height && michael@0: srcSurface->Stride() == destSurface->Stride(), michael@0: "Source and destination surfaces don't have identical characteristics"); michael@0: michael@0: MOZ_ASSERT(srcSurface->Stride() == srcSize.width * 4, michael@0: "Source surface stride isn't tightly packed"); michael@0: michael@0: // Only premultiply ARGB32 michael@0: if (srcSurface->GetFormat() != SurfaceFormat::B8G8R8A8) { michael@0: if (destSurface != srcSurface) { michael@0: memcpy(destSurface->GetData(), srcSurface->GetData(), michael@0: srcSurface->Stride() * srcSize.height); michael@0: } michael@0: return; michael@0: } michael@0: michael@0: uint8_t *src = srcSurface->GetData(); michael@0: uint8_t *dst = destSurface->GetData(); michael@0: michael@0: // Assert that our endian define is correct. michael@0: ASSERT_ENDIAN(); michael@0: michael@0: uint32_t dim = srcSize.width * srcSize.height; michael@0: for (uint32_t i = 0; i < dim; ++i) { michael@0: #ifdef MOZ_LITTLE_ENDIAN michael@0: uint8_t b = *src++; michael@0: uint8_t g = *src++; michael@0: uint8_t r = *src++; michael@0: uint8_t a = *src++; michael@0: michael@0: *dst++ = PremultiplyValue(a, b); michael@0: *dst++ = PremultiplyValue(a, g); michael@0: *dst++ = PremultiplyValue(a, r); michael@0: *dst++ = a; michael@0: #else michael@0: uint8_t a = *src++; michael@0: uint8_t r = *src++; michael@0: uint8_t g = *src++; michael@0: uint8_t b = *src++; michael@0: michael@0: *dst++ = a; michael@0: *dst++ = PremultiplyValue(a, r); michael@0: *dst++ = PremultiplyValue(a, g); michael@0: *dst++ = PremultiplyValue(a, b); michael@0: #endif michael@0: } michael@0: } michael@0: michael@0: michael@0: } michael@0: }