blob: 563933f13a03c16e880c2b8132c7df3657fc4868 [file] [log] [blame]
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkColorPriv.h"
#include "SkSwizzler.h"
#include "SkTemplates.h"
// index
#define A32_MASK_IN_PLACE (SkPMColor)(SK_A32_MASK << SK_A32_SHIFT)
static bool swizzle_index_to_n32(void* SK_RESTRICT dstRow,
const uint8_t* SK_RESTRICT src,
int width, int deltaSrc, int, const SkPMColor ctable[]) {
SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
SkPMColor cc = A32_MASK_IN_PLACE;
for (int x = 0; x < width; x++) {
SkPMColor c = ctable[*src];
cc &= c;
dst[x] = c;
src += deltaSrc;
}
return cc != A32_MASK_IN_PLACE;
}
static bool swizzle_index_to_n32_skipZ(void* SK_RESTRICT dstRow,
const uint8_t* SK_RESTRICT src,
int width, int deltaSrc, int,
const SkPMColor ctable[]) {
SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
SkPMColor cc = A32_MASK_IN_PLACE;
for (int x = 0; x < width; x++) {
SkPMColor c = ctable[*src];
cc &= c;
if (c != 0) {
dst[x] = c;
}
src += deltaSrc;
}
return cc != A32_MASK_IN_PLACE;
}
#undef A32_MASK_IN_PLACE
// n32
static bool swizzle_rgbx_to_n32(void* SK_RESTRICT dstRow,
const uint8_t* SK_RESTRICT src,
int width, int deltaSrc, int, const SkPMColor[]) {
SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
for (int x = 0; x < width; x++) {
dst[x] = SkPackARGB32(0xFF, src[0], src[1], src[2]);
src += deltaSrc;
}
return false;
}
static bool swizzle_rgba_to_n32_premul(void* SK_RESTRICT dstRow,
const uint8_t* SK_RESTRICT src,
int width, int deltaSrc, int, const SkPMColor[]) {
SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
unsigned alphaMask = 0xFF;
for (int x = 0; x < width; x++) {
unsigned alpha = src[3];
dst[x] = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
src += deltaSrc;
alphaMask &= alpha;
}
return alphaMask != 0xFF;
}
static bool swizzle_rgba_to_n32_unpremul(void* SK_RESTRICT dstRow,
const uint8_t* SK_RESTRICT src,
int width, int deltaSrc, int,
const SkPMColor[]) {
uint32_t* SK_RESTRICT dst = reinterpret_cast<uint32_t*>(dstRow);
unsigned alphaMask = 0xFF;
for (int x = 0; x < width; x++) {
unsigned alpha = src[3];
dst[x] = SkPackARGB32NoCheck(alpha, src[0], src[1], src[2]);
src += deltaSrc;
alphaMask &= alpha;
}
return alphaMask != 0xFF;
}
static bool swizzle_rgba_to_n32_premul_skipZ(void* SK_RESTRICT dstRow,
const uint8_t* SK_RESTRICT src,
int width, int deltaSrc, int,
const SkPMColor[]) {
SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
unsigned alphaMask = 0xFF;
for (int x = 0; x < width; x++) {
unsigned alpha = src[3];
if (0 != alpha) {
dst[x] = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
}
src += deltaSrc;
alphaMask &= alpha;
}
return alphaMask != 0xFF;
}
/**
FIXME: This was my idea to cheat in order to continue taking advantage of skipping zeroes.
This would be fine for drawing normally, but not for drawing with transfer modes. Being
honest means we can draw correctly with transfer modes, with the cost of not being able
to take advantage of Android's free unwritten pages. Something to keep in mind when we
decide whether to switch to unpremul default.
static bool swizzle_rgba_to_n32_unpremul_skipZ(void* SK_RESTRICT dstRow,
const uint8_t* SK_RESTRICT src,
int width, int deltaSrc, int,
const SkPMColor[]) {
SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
unsigned alphaMask = 0xFF;
for (int x = 0; x < width; x++) {
unsigned alpha = src[3];
// NOTE: We cheat here. The caller requested unpremul and skip zeroes. It's possible
// the color components are not zero, but we skip them anyway, meaning they'll remain
// zero (implied by the request to skip zeroes).
if (0 != alpha) {
dst[x] = SkPackARGB32NoCheck(alpha, src[0], src[1], src[2]);
}
src += deltaSrc;
alphaMask &= alpha;
}
return alphaMask != 0xFF;
}
*/
SkSwizzler* SkSwizzler::CreateSwizzler(SkSwizzler::SrcConfig sc, const SkPMColor* ctable,
const SkImageInfo& info, void* dst,
size_t dstRowBytes, bool skipZeroes) {
if (info.colorType() == kUnknown_SkColorType) {
return NULL;
}
if (info.minRowBytes() > dstRowBytes) {
return NULL;
}
if (kIndex == sc && NULL == ctable) {
return NULL;
}
RowProc proc = NULL;
switch (sc) {
case kIndex:
switch (info.colorType()) {
case kN32_SkColorType:
// We assume the color premultiplied ctable (or not) as desired.
if (skipZeroes) {
proc = &swizzle_index_to_n32_skipZ;
} else {
proc = &swizzle_index_to_n32;
}
break;
default:
break;
}
break;
case kRGBX:
// TODO: Support other swizzles.
switch (info.colorType()) {
case kN32_SkColorType:
proc = &swizzle_rgbx_to_n32;
break;
default:
break;
}
break;
case kRGBA:
switch (info.colorType()) {
case kN32_SkColorType:
if (info.alphaType() == kUnpremul_SkAlphaType) {
// Respect skipZeroes?
proc = &swizzle_rgba_to_n32_unpremul;
} else {
if (skipZeroes) {
proc = &swizzle_rgba_to_n32_premul_skipZ;
} else {
proc = &swizzle_rgba_to_n32_premul;
}
}
break;
default:
break;
}
break;
default:
break;
}
if (NULL == proc) {
return NULL;
}
return SkNEW_ARGS(SkSwizzler, (proc, ctable, BytesPerPixel(sc), info, dst, dstRowBytes));
}
SkSwizzler::SkSwizzler(RowProc proc, const SkPMColor* ctable, int srcBpp,
const SkImageInfo& info, void* dst, size_t rowBytes)
: fRowProc(proc)
, fColorTable(ctable)
, fSrcPixelSize(srcBpp)
, fDstInfo(info)
, fDstRow(dst)
, fDstRowBytes(rowBytes)
, fCurrY(0)
{
}
bool SkSwizzler::next(const uint8_t* SK_RESTRICT src) {
SkASSERT(fCurrY < fDstInfo.height());
const bool hadAlpha = fRowProc(fDstRow, src, fDstInfo.width(), fSrcPixelSize,
fCurrY, fColorTable);
fCurrY++;
fDstRow = SkTAddOffset<void>(fDstRow, fDstRowBytes);
return hadAlpha;
}