/*
* 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 "SkCodecPriv.h"
#include "SkColorPriv.h"
#include "SkMaskSwizzler.h"
static void swizzle_mask16_to_n32_opaque(
void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks,
uint32_t startX, uint32_t sampleX) {
// Use the masks to decode to the destination
uint16_t* srcPtr = ((uint16_t*) srcRow) + startX;
SkPMColor* dstPtr = (SkPMColor*) dstRow;
for (int i = 0; i < width; i++) {
uint16_t p = srcPtr[0];
uint8_t red = masks->getRed(p);
uint8_t green = masks->getGreen(p);
uint8_t blue = masks->getBlue(p);
dstPtr[i] = SkPackARGB32NoCheck(0xFF, red, green, blue);
srcPtr += sampleX;
}
}
static void swizzle_mask16_to_n32_unpremul(
void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks,
uint32_t startX, uint32_t sampleX) {
// Use the masks to decode to the destination
uint16_t* srcPtr = ((uint16_t*) srcRow) + startX;
SkPMColor* dstPtr = (SkPMColor*) dstRow;
for (int i = 0; i < width; i++) {
uint16_t p = srcPtr[0];
uint8_t red = masks->getRed(p);
uint8_t green = masks->getGreen(p);
uint8_t blue = masks->getBlue(p);
uint8_t alpha = masks->getAlpha(p);
dstPtr[i] = SkPackARGB32NoCheck(alpha, red, green, blue);
srcPtr += sampleX;
}
}
static void swizzle_mask16_to_n32_premul(
void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks,
uint32_t startX, uint32_t sampleX) {
// Use the masks to decode to the destination
uint16_t* srcPtr = ((uint16_t*) srcRow) + startX;
SkPMColor* dstPtr = (SkPMColor*) dstRow;
for (int i = 0; i < width; i++) {
uint16_t p = srcPtr[0];
uint8_t red = masks->getRed(p);
uint8_t green = masks->getGreen(p);
uint8_t blue = masks->getBlue(p);
uint8_t alpha = masks->getAlpha(p);
dstPtr[i] = SkPreMultiplyARGB(alpha, red, green, blue);
srcPtr += sampleX;
}
}
// TODO (msarett): We have promoted a two byte per pixel image to 8888, only to
// convert it back to 565. Instead, we should swizzle to 565 directly.
static void swizzle_mask16_to_565(
void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks,
uint32_t startX, uint32_t sampleX) {
// Use the masks to decode to the destination
uint16_t* srcPtr = ((uint16_t*) srcRow) + startX;
uint16_t* dstPtr = (uint16_t*) dstRow;
for (int i = 0; i < width; i++) {
uint16_t p = srcPtr[0];
uint8_t red = masks->getRed(p);
uint8_t green = masks->getGreen(p);
uint8_t blue = masks->getBlue(p);
dstPtr[i] = SkPack888ToRGB16(red, green, blue);
srcPtr += sampleX;
}
}
static void swizzle_mask24_to_n32_opaque(
void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks,
uint32_t startX, uint32_t sampleX) {
// Use the masks to decode to the destination
srcRow += 3 * startX;
SkPMColor* dstPtr = (SkPMColor*) dstRow;
for (int i = 0; i < width; i++) {
uint32_t p = srcRow[0] | (srcRow[1] << 8) | srcRow[2] << 16;
uint8_t red = masks->getRed(p);
uint8_t green = masks->getGreen(p);
uint8_t blue = masks->getBlue(p);
dstPtr[i] = SkPackARGB32NoCheck(0xFF, red, green, blue);
srcRow += 3 * sampleX;
}
}
static void swizzle_mask24_to_n32_unpremul(
void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks,
uint32_t startX, uint32_t sampleX) {
// Use the masks to decode to the destination
srcRow += 3 * startX;
SkPMColor* dstPtr = (SkPMColor*) dstRow;
for (int i = 0; i < width; i++) {
uint32_t p = srcRow[0] | (srcRow[1] << 8) | srcRow[2] << 16;
uint8_t red = masks->getRed(p);
uint8_t green = masks->getGreen(p);
uint8_t blue = masks->getBlue(p);
uint8_t alpha = masks->getAlpha(p);
dstPtr[i] = SkPackARGB32NoCheck(alpha, red, green, blue);
srcRow += 3 * sampleX;
}
}
static void swizzle_mask24_to_n32_premul(
void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks,
uint32_t startX, uint32_t sampleX) {
// Use the masks to decode to the destination
srcRow += 3 * startX;
SkPMColor* dstPtr = (SkPMColor*) dstRow;
for (int i = 0; i < width; i++) {
uint32_t p = srcRow[0] | (srcRow[1] << 8) | srcRow[2] << 16;
uint8_t red = masks->getRed(p);
uint8_t green = masks->getGreen(p);
uint8_t blue = masks->getBlue(p);
uint8_t alpha = masks->getAlpha(p);
dstPtr[i] = SkPreMultiplyARGB(alpha, red, green, blue);
srcRow += 3 * sampleX;
}
}
static void swizzle_mask24_to_565(
void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks,
uint32_t startX, uint32_t sampleX) {
// Use the masks to decode to the destination
srcRow += 3 * startX;
uint16_t* dstPtr = (uint16_t*) dstRow;
for (int i = 0; i < width; i++) {
uint32_t p = srcRow[0] | (srcRow[1] << 8) | srcRow[2] << 16;
uint8_t red = masks->getRed(p);
uint8_t green = masks->getGreen(p);
uint8_t blue = masks->getBlue(p);
dstPtr[i] = SkPack888ToRGB16(red, green, blue);
srcRow += 3 * sampleX;
}
}
static void swizzle_mask32_to_n32_opaque(
void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks,
uint32_t startX, uint32_t sampleX) {
// Use the masks to decode to the destination
uint32_t* srcPtr = ((uint32_t*) srcRow) + startX;
SkPMColor* dstPtr = (SkPMColor*) dstRow;
for (int i = 0; i < width; i++) {
uint32_t p = srcPtr[0];
uint8_t red = masks->getRed(p);
uint8_t green = masks->getGreen(p);
uint8_t blue = masks->getBlue(p);
dstPtr[i] = SkPackARGB32NoCheck(0xFF, red, green, blue);
srcPtr += sampleX;
}
}
static void swizzle_mask32_to_n32_unpremul(
void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks,
uint32_t startX, uint32_t sampleX) {
// Use the masks to decode to the destination
uint32_t* srcPtr = ((uint32_t*) srcRow) + startX;
SkPMColor* dstPtr = (SkPMColor*) dstRow;
for (int i = 0; i < width; i++) {
uint32_t p = srcPtr[0];
uint8_t red = masks->getRed(p);
uint8_t green = masks->getGreen(p);
uint8_t blue = masks->getBlue(p);
uint8_t alpha = masks->getAlpha(p);
dstPtr[i] = SkPackARGB32NoCheck(alpha, red, green, blue);
srcPtr += sampleX;
}
}
static void swizzle_mask32_to_n32_premul(
void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks,
uint32_t startX, uint32_t sampleX) {
// Use the masks to decode to the destination
uint32_t* srcPtr = ((uint32_t*) srcRow) + startX;
SkPMColor* dstPtr = (SkPMColor*) dstRow;
for (int i = 0; i < width; i++) {
uint32_t p = srcPtr[0];
uint8_t red = masks->getRed(p);
uint8_t green = masks->getGreen(p);
uint8_t blue = masks->getBlue(p);
uint8_t alpha = masks->getAlpha(p);
dstPtr[i] = SkPreMultiplyARGB(alpha, red, green, blue);
srcPtr += sampleX;
}
}
static void swizzle_mask32_to_565(
void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks,
uint32_t startX, uint32_t sampleX) {
// Use the masks to decode to the destination
uint32_t* srcPtr = ((uint32_t*) srcRow) + startX;
uint16_t* dstPtr = (uint16_t*) dstRow;
for (int i = 0; i < width; i++) {
uint32_t p = srcPtr[0];
uint8_t red = masks->getRed(p);
uint8_t green = masks->getGreen(p);
uint8_t blue = masks->getBlue(p);
dstPtr[i] = SkPack888ToRGB16(red, green, blue);
srcPtr += sampleX;
}
}
/*
*
* Create a new mask swizzler
*
*/
SkMaskSwizzler* SkMaskSwizzler::CreateMaskSwizzler(const SkImageInfo& dstInfo,
const SkImageInfo& srcInfo, SkMasks* masks, uint32_t bitsPerPixel,
const SkCodec::Options& options) {
// Choose the appropriate row procedure
RowProc proc = nullptr;
switch (bitsPerPixel) {
case 16:
switch (dstInfo.colorType()) {
case kN32_SkColorType:
if (kOpaque_SkAlphaType == srcInfo.alphaType()) {
proc = &swizzle_mask16_to_n32_opaque;
} else {
switch (dstInfo.alphaType()) {
case kUnpremul_SkAlphaType:
proc = &swizzle_mask16_to_n32_unpremul;
break;
case kPremul_SkAlphaType:
proc = &swizzle_mask16_to_n32_premul;
break;
default:
break;
}
}
break;
case kRGB_565_SkColorType:
proc = &swizzle_mask16_to_565;
break;
default:
break;
}
break;
case 24:
switch (dstInfo.colorType()) {
case kN32_SkColorType:
if (kOpaque_SkAlphaType == srcInfo.alphaType()) {
proc = &swizzle_mask24_to_n32_opaque;
} else {
switch (dstInfo.alphaType()) {
case kUnpremul_SkAlphaType:
proc = &swizzle_mask24_to_n32_unpremul;
break;
case kPremul_SkAlphaType:
proc = &swizzle_mask24_to_n32_premul;
break;
default:
break;
}
}
break;
case kRGB_565_SkColorType:
proc = &swizzle_mask24_to_565;
break;
default:
break;
}
break;
case 32:
switch (dstInfo.colorType()) {
case kN32_SkColorType:
if (kOpaque_SkAlphaType == srcInfo.alphaType()) {
proc = &swizzle_mask32_to_n32_opaque;
} else {
switch (dstInfo.alphaType()) {
case kUnpremul_SkAlphaType:
proc = &swizzle_mask32_to_n32_unpremul;
break;
case kPremul_SkAlphaType:
proc = &swizzle_mask32_to_n32_premul;
break;
default:
break;
}
}
break;
case kRGB_565_SkColorType:
proc = &swizzle_mask32_to_565;
break;
default:
break;
}
break;
default:
SkASSERT(false);
return nullptr;
}
int srcOffset = 0;
int srcWidth = dstInfo.width();
if (options.fSubset) {
srcOffset = options.fSubset->left();
srcWidth = options.fSubset->width();
}
return new SkMaskSwizzler(masks, proc, srcOffset, srcWidth);
}
/*
*
* Constructor for mask swizzler
*
*/
SkMaskSwizzler::SkMaskSwizzler(SkMasks* masks, RowProc proc, int srcOffset, int subsetWidth)
: fMasks(masks)
, fRowProc(proc)
, fSubsetWidth(subsetWidth)
, fDstWidth(subsetWidth)
, fSampleX(1)
, fSrcOffset(srcOffset)
, fX0(srcOffset)
{}
int SkMaskSwizzler::onSetSampleX(int sampleX) {
// FIXME: Share this function with SkSwizzler?
SkASSERT(sampleX > 0); // Surely there is an upper limit? Should there be
// way to report failure?
fSampleX = sampleX;
fX0 = get_start_coord(sampleX) + fSrcOffset;
fDstWidth = get_scaled_dimension(fSubsetWidth, sampleX);
// check that fX0 is valid
SkASSERT(fX0 >= 0);
return fDstWidth;
}
/*
*
* Swizzle the specified row
*
*/
void SkMaskSwizzler::swizzle(void* dst, const uint8_t* SK_RESTRICT src) {
SkASSERT(nullptr != dst && nullptr != src);
fRowProc(dst, src, fDstWidth, fMasks, fX0, fSampleX);
}