#include "SkConfig8888.h"
#include "SkColorPriv.h"
#include "SkMathPriv.h"
#include "SkUnPreMultiply.h"
enum AlphaVerb {
kNothing_AlphaVerb,
kPremul_AlphaVerb,
kUnpremul_AlphaVerb,
};
template <bool doSwapRB, AlphaVerb doAlpha> uint32_t convert32(uint32_t c) {
if (doSwapRB) {
c = SkSwizzle_RB(c);
}
// Lucky for us, in both RGBA and BGRA, the alpha component is always in the same place, so
// we can perform premul or unpremul the same way without knowing the swizzles for RGB.
switch (doAlpha) {
case kNothing_AlphaVerb:
// no change
break;
case kPremul_AlphaVerb:
c = SkPreMultiplyARGB(SkGetPackedA32(c), SkGetPackedR32(c),
SkGetPackedG32(c), SkGetPackedB32(c));
break;
case kUnpremul_AlphaVerb:
c = SkUnPreMultiply::UnPreMultiplyPreservingByteOrder(c);
break;
}
return c;
}
template <bool doSwapRB, AlphaVerb doAlpha>
void convert32_row(uint32_t* dst, const uint32_t* src, int count) {
// This has to be correct if src == dst (but not partial overlap)
for (int i = 0; i < count; ++i) {
dst[i] = convert32<doSwapRB, doAlpha>(src[i]);
}
}
static bool is_32bit_colortype(SkColorType ct) {
return kRGBA_8888_SkColorType == ct || kBGRA_8888_SkColorType == ct;
}
static AlphaVerb compute_AlphaVerb(SkAlphaType src, SkAlphaType dst) {
SkASSERT(kIgnore_SkAlphaType != src);
SkASSERT(kIgnore_SkAlphaType != dst);
if (kOpaque_SkAlphaType == src || kOpaque_SkAlphaType == dst || src == dst) {
return kNothing_AlphaVerb;
}
if (kPremul_SkAlphaType == dst) {
SkASSERT(kUnpremul_SkAlphaType == src);
return kPremul_AlphaVerb;
} else {
SkASSERT(kPremul_SkAlphaType == src);
SkASSERT(kUnpremul_SkAlphaType == dst);
return kUnpremul_AlphaVerb;
}
}
static void memcpy32_row(uint32_t* dst, const uint32_t* src, int count) {
memcpy(dst, src, count * 4);
}
bool SkSrcPixelInfo::convertPixelsTo(SkDstPixelInfo* dst, int width, int height) const {
if (width <= 0 || height <= 0) {
return false;
}
if (!is_32bit_colortype(fColorType) || !is_32bit_colortype(dst->fColorType)) {
return false;
}
void (*proc)(uint32_t* dst, const uint32_t* src, int count);
AlphaVerb doAlpha = compute_AlphaVerb(fAlphaType, dst->fAlphaType);
bool doSwapRB = fColorType != dst->fColorType;
switch (doAlpha) {
case kNothing_AlphaVerb:
if (doSwapRB) {
proc = convert32_row<true, kNothing_AlphaVerb>;
} else {
if (fPixels == dst->fPixels) {
return true;
}
proc = memcpy32_row;
}
break;
case kPremul_AlphaVerb:
if (doSwapRB) {
proc = convert32_row<true, kPremul_AlphaVerb>;
} else {
proc = convert32_row<false, kPremul_AlphaVerb>;
}
break;
case kUnpremul_AlphaVerb:
if (doSwapRB) {
proc = convert32_row<true, kUnpremul_AlphaVerb>;
} else {
proc = convert32_row<false, kUnpremul_AlphaVerb>;
}
break;
}
uint32_t* dstP = static_cast<uint32_t*>(dst->fPixels);
const uint32_t* srcP = static_cast<const uint32_t*>(fPixels);
size_t srcInc = fRowBytes >> 2;
size_t dstInc = dst->fRowBytes >> 2;
for (int y = 0; y < height; ++y) {
proc(dstP, srcP, width);
dstP += dstInc;
srcP += srcInc;
}
return true;
}