1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/layers/LayerUtils.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,101 @@ 1.4 +/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "LayerUtils.h" 1.10 +#include "PremultiplyTables.h" 1.11 +#include "mozilla/Endian.h" 1.12 + 1.13 +namespace mozilla { 1.14 +namespace layers { 1.15 + 1.16 +using namespace mozilla::gfx; 1.17 + 1.18 +static inline const uint8_t PremultiplyValue(uint8_t a, uint8_t v) { 1.19 + return PremultiplyTable[a*256+v]; 1.20 +} 1.21 + 1.22 +static inline const uint8_t UnpremultiplyValue(uint8_t a, uint8_t v) { 1.23 + return UnpremultiplyTable[a*256+v]; 1.24 +} 1.25 + 1.26 +#ifdef DEBUG 1.27 +static bool IsLittleEndian() 1.28 +{ 1.29 + // Violate strict aliasing, because violating strict aliasing is how 1.30 + // we always pack and unpack between uint32_t and uint8_t[]. 1.31 + uint16_t testShort; 1.32 + static const uint8_t testBytes[2] = { 0xAA, 0xBB }; 1.33 + memcpy(&testShort, testBytes, sizeof(testBytes)); 1.34 + return testShort == 0xBBAA; 1.35 +} 1.36 +#endif // DEBUG 1.37 + 1.38 +#ifdef MOZ_LITTLE_ENDIAN 1.39 +#define ASSERT_ENDIAN() MOZ_ASSERT(IsLittleEndian(), "Defined as little endian, but actually big!") 1.40 +#else 1.41 +#define ASSERT_ENDIAN() MOZ_ASSERT(!IsLittleEndian(), "Defined as big endian, but actually little!") 1.42 +#endif 1.43 + 1.44 +void 1.45 +PremultiplySurface(DataSourceSurface* srcSurface, 1.46 + DataSourceSurface* destSurface) 1.47 +{ 1.48 + if (!destSurface) 1.49 + destSurface = srcSurface; 1.50 + 1.51 + IntSize srcSize = srcSurface->GetSize(); 1.52 + MOZ_ASSERT(srcSurface->GetFormat() == destSurface->GetFormat() && 1.53 + srcSize.width == destSurface->GetSize().width && 1.54 + srcSize.height == destSurface->GetSize().height && 1.55 + srcSurface->Stride() == destSurface->Stride(), 1.56 + "Source and destination surfaces don't have identical characteristics"); 1.57 + 1.58 + MOZ_ASSERT(srcSurface->Stride() == srcSize.width * 4, 1.59 + "Source surface stride isn't tightly packed"); 1.60 + 1.61 + // Only premultiply ARGB32 1.62 + if (srcSurface->GetFormat() != SurfaceFormat::B8G8R8A8) { 1.63 + if (destSurface != srcSurface) { 1.64 + memcpy(destSurface->GetData(), srcSurface->GetData(), 1.65 + srcSurface->Stride() * srcSize.height); 1.66 + } 1.67 + return; 1.68 + } 1.69 + 1.70 + uint8_t *src = srcSurface->GetData(); 1.71 + uint8_t *dst = destSurface->GetData(); 1.72 + 1.73 + // Assert that our endian define is correct. 1.74 + ASSERT_ENDIAN(); 1.75 + 1.76 + uint32_t dim = srcSize.width * srcSize.height; 1.77 + for (uint32_t i = 0; i < dim; ++i) { 1.78 +#ifdef MOZ_LITTLE_ENDIAN 1.79 + uint8_t b = *src++; 1.80 + uint8_t g = *src++; 1.81 + uint8_t r = *src++; 1.82 + uint8_t a = *src++; 1.83 + 1.84 + *dst++ = PremultiplyValue(a, b); 1.85 + *dst++ = PremultiplyValue(a, g); 1.86 + *dst++ = PremultiplyValue(a, r); 1.87 + *dst++ = a; 1.88 +#else 1.89 + uint8_t a = *src++; 1.90 + uint8_t r = *src++; 1.91 + uint8_t g = *src++; 1.92 + uint8_t b = *src++; 1.93 + 1.94 + *dst++ = a; 1.95 + *dst++ = PremultiplyValue(a, r); 1.96 + *dst++ = PremultiplyValue(a, g); 1.97 + *dst++ = PremultiplyValue(a, b); 1.98 +#endif 1.99 + } 1.100 +} 1.101 + 1.102 + 1.103 +} 1.104 +}