зеркало из https://github.com/mozilla/gecko-dev.git
102 строки
2.9 KiB
C++
102 строки
2.9 KiB
C++
/* -*- 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
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|