/*
|
* 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;
|
}
|
}
|