/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkCoreBlitters.h"
#include "SkColorData.h"
#include "SkShader.h"
#include "SkUTF.h"
#include "SkXfermodePriv.h"
#include "SkColorData.h"
#include "SkNx.h"
static void D16_S32X_src(uint16_t dst[], const SkPMColor src[], int count, uint8_t coverage) {
SkASSERT(coverage == 0xFF);
for (int i = 0; i < count; ++i) {
dst[i] = SkPixel32ToPixel16(src[i]);
}
}
static void D16_S32X_src_coverage(uint16_t dst[], const SkPMColor src[], int count,
uint8_t coverage) {
switch (coverage) {
case 0: break;
case 0xFF:
for (int i = 0; i < count; ++i) {
dst[i] = SkPixel32ToPixel16(src[i]);
}
break;
default:
unsigned scale = coverage + (coverage >> 7);
for (int i = 0; i < count; ++i) {
dst[i] = SkSrcOver32To16(SkAlphaMulQ(src[i], scale), dst[i]);
}
break;
}
}
static void D16_S32A_srcover(uint16_t dst[], const SkPMColor src[], int count, uint8_t coverage) {
SkASSERT(coverage == 0xFF);
for (int i = 0; i < count; ++i) {
dst[i] = SkSrcOver32To16(src[i], dst[i]);
}
}
static void D16_S32A_srcover_coverage(uint16_t dst[], const SkPMColor src[], int count,
uint8_t coverage) {
switch (coverage) {
case 0: break;
case 0xFF:
for (int i = 0; i < count; ++i) {
dst[i] = SkSrcOver32To16(src[i], dst[i]);
}
break;
default:
unsigned scale = coverage + (coverage >> 7);
for (int i = 0; i < count; ++i) {
dst[i] = SkSrcOver32To16(SkAlphaMulQ(src[i], scale), dst[i]);
}
break;
}
}
bool SkRGB565_Shader_Blitter::Supports(const SkPixmap& device, const SkPaint& paint) {
if (device.colorType() != kRGB_565_SkColorType) {
return false;
}
if (device.colorSpace()) {
return false;
}
if (paint.getBlendMode() != SkBlendMode::kSrcOver &&
paint.getBlendMode() != SkBlendMode::kSrc) {
return false;
}
if (paint.isDither()) {
return false;
}
return true;
}
SkRGB565_Shader_Blitter::SkRGB565_Shader_Blitter(const SkPixmap& device,
const SkPaint& paint, SkShaderBase::Context* shaderContext)
: INHERITED(device, paint, shaderContext)
{
SkASSERT(shaderContext);
SkASSERT(Supports(device, paint));
fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * (sizeof(SkPMColor)));
bool isOpaque = SkToBool(shaderContext->getFlags() & SkShaderBase::kOpaqueAlpha_Flag);
if (paint.getBlendMode() == SkBlendMode::kSrc || isOpaque) {
fBlend = D16_S32X_src;
fBlendCoverage = D16_S32X_src_coverage;
} else { // srcover
fBlend = isOpaque ? D16_S32X_src : D16_S32A_srcover;
fBlendCoverage = isOpaque ? D16_S32X_src_coverage : D16_S32A_srcover_coverage;
}
}
SkRGB565_Shader_Blitter::~SkRGB565_Shader_Blitter() {
sk_free(fBuffer);
}
void SkRGB565_Shader_Blitter::blitH(int x, int y, int width) {
SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width());
uint16_t* device = fDevice.writable_addr16(x, y);
SkPMColor* span = fBuffer;
fShaderContext->shadeSpan(x, y, span, width);
fBlend(device, span, width, 0xFF);
}
void SkRGB565_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha coverage[],
const int16_t runs[]) {
SkPMColor* span = fBuffer;
uint16_t* device = fDevice.writable_addr16(x, y);
auto* shaderContext = fShaderContext;
for (;;) {
int count = *runs;
if (count <= 0) {
break;
}
int aa = *coverage;
if (aa) {
shaderContext->shadeSpan(x, y, span, count);
fBlendCoverage(device, span, count, aa);
}
device += count;
runs += count;
coverage += count;
x += count;
}
}