blob: 01fd70425423967cc835f4e93d3226af9fa4793e [file] [log] [blame]
/*
* Copyright 2016 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 "SkColorPriv.h"
#include "SkShader.h"
#include "SkUtils.h"
#include "SkXfermode.h"
#include "SkBlitMask.h"
#include "SkTemplates.h"
template <typename State> class SkState_Blitter : public SkRasterBlitter {
typedef SkRasterBlitter INHERITED;
State fState;
public:
SkState_Blitter(const SkPixmap& device, const SkPaint& paint)
: INHERITED(device)
, fState(device.info(), paint, nullptr)
{}
void blitH(int x, int y, int width) override {
SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width());
fState.fProc1(fState, State::WritableAddr(fDevice, x, y), fState.fPM4f, width, nullptr);
}
void blitV(int x, int y, int height, SkAlpha alpha) override {
SkASSERT(x >= 0 && y >= 0 && y + height <= fDevice.height());
typename State::DstType* device = State::WritableAddr(fDevice, x, y);
size_t deviceRB = fDevice.rowBytes();
for (int i = 0; i < height; ++i) {
fState.fProc1(fState, device, fState.fPM4f, 1, &alpha);
device = (typename State::DstType*)((char*)device + deviceRB);
}
}
void blitRect(int x, int y, int width, int height) override {
SkASSERT(x >= 0 && y >= 0 &&
x + width <= fDevice.width() && y + height <= fDevice.height());
typename State::DstType* device = State::WritableAddr(fDevice, x, y);
size_t deviceRB = fDevice.rowBytes();
do {
fState.fProc1(fState, device, fState.fPM4f, width, nullptr);
y += 1;
device = (typename State::DstType*)((char*)device + deviceRB);
} while (--height > 0);
}
void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) override {
typename State::DstType* device = State::WritableAddr(fDevice, x, y);
for (;;) {
int count = *runs;
if (count <= 0) {
break;
}
int aa = *antialias;
if (aa) {
if (aa == 255) {
fState.fProc1(fState, device, fState.fPM4f, count, nullptr);
} else {
for (int i = 0; i < count; ++i) {
fState.fProc1(fState, &device[i], fState.fPM4f, 1, antialias);
}
}
}
device += count;
runs += count;
antialias += count;
x += count;
}
}
void blitMask(const SkMask& mask, const SkIRect& clip) override {
// we only handle kA8
if (SkMask::kA8_Format != mask.fFormat) {
this->INHERITED::blitMask(mask, clip);
return;
}
SkASSERT(mask.fBounds.contains(clip));
const int x = clip.fLeft;
const int width = clip.width();
const int y = clip.fTop;
const int height = clip.height();
typename State::DstType* device = State::WritableAddr(fDevice, x, y);
const size_t dstRB = fDevice.rowBytes();
const uint8_t* maskRow = (const uint8_t*)mask.getAddr(x, y);
const size_t maskRB = mask.fRowBytes;
for (int i = 0; i < height; ++i) {
fState.fProc1(fState, device, fState.fPM4f, width, maskRow);
device = (typename State::DstType*)((char*)device + dstRB);
maskRow += maskRB;
}
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////
template <typename State> class SkState_Shader_Blitter : public SkShaderBlitter {
public:
SkState_Shader_Blitter(const SkPixmap& device, const SkPaint& paint,
SkShader::Context* shaderContext)
: INHERITED(device, paint, shaderContext)
, fState(device.info(), paint, shaderContext)
{}
void blitH(int x, int y, int width) override {
SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width());
typename State::DstType* device = State::WritableAddr(fDevice, x, y);
fShaderContext->shadeSpan4f(x, y, fState.fBuffer, width);
fState.fProcN(fState, device, fState.fBuffer, width, nullptr);
}
void blitV(int x, int y, int height, SkAlpha alpha) override {
SkASSERT(x >= 0 && y >= 0 && y + height <= fDevice.height());
typename State::DstType* device = State::WritableAddr(fDevice, x, y);
size_t deviceRB = fDevice.rowBytes();
const int bottom = y + height;
if (fConstInY) {
fShaderContext->shadeSpan4f(x, y, fState.fBuffer, 1);
}
for (; y < bottom; ++y) {
if (!fConstInY) {
fShaderContext->shadeSpan4f(x, y, fState.fBuffer, 1);
}
fState.fProcN(fState, device, fState.fBuffer, 1, &alpha);
device = (typename State::DstType*)((char*)device + deviceRB);
}
}
void blitRect(int x, int y, int width, int height) override {
SkASSERT(x >= 0 && y >= 0 &&
x + width <= fDevice.width() && y + height <= fDevice.height());
typename State::DstType* device = State::WritableAddr(fDevice, x, y);
size_t deviceRB = fDevice.rowBytes();
const int bottom = y + height;
if (fConstInY) {
fShaderContext->shadeSpan4f(x, y, fState.fBuffer, width);
}
for (; y < bottom; ++y) {
if (!fConstInY) {
fShaderContext->shadeSpan4f(x, y, fState.fBuffer, width);
}
fState.fProcN(fState, device, fState.fBuffer, width, nullptr);
device = (typename State::DstType*)((char*)device + deviceRB);
}
}
void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) override {
typename State::DstType* device = State::WritableAddr(fDevice, x, y);
for (;;) {
int count = *runs;
if (count <= 0) {
break;
}
int aa = *antialias;
if (aa) {
fShaderContext->shadeSpan4f(x, y, fState.fBuffer, count);
if (aa == 255) {
fState.fProcN(fState, device, fState.fBuffer, count, nullptr);
} else {
for (int i = 0; i < count; ++i) {
fState.fProcN(fState, &device[i], &fState.fBuffer[i], 1, antialias);
}
}
}
device += count;
runs += count;
antialias += count;
x += count;
}
}
void blitMask(const SkMask& mask, const SkIRect& clip) override {
// we only handle kA8
if (SkMask::kA8_Format != mask.fFormat) {
this->INHERITED::blitMask(mask, clip);
return;
}
SkASSERT(mask.fBounds.contains(clip));
const int x = clip.fLeft;
const int width = clip.width();
int y = clip.fTop;
typename State::DstType* device = State::WritableAddr(fDevice, x, y);
const size_t deviceRB = fDevice.rowBytes();
const uint8_t* maskRow = (const uint8_t*)mask.getAddr(x, y);
const size_t maskRB = mask.fRowBytes;
if (fConstInY) {
fShaderContext->shadeSpan4f(x, y, fState.fBuffer, width);
}
for (; y < clip.fBottom; ++y) {
if (!fConstInY) {
fShaderContext->shadeSpan4f(x, y, fState.fBuffer, width);
}
fState.fProcN(fState, device, fState.fBuffer, width, maskRow);
device = (typename State::DstType*)((char*)device + deviceRB);
maskRow += maskRB;
}
}
private:
State fState;
typedef SkShaderBlitter INHERITED;
};
//////////////////////////////////////////////////////////////////////////////////////
static bool is_opaque(const SkPaint& paint, const SkShader::Context* shaderContext) {
return shaderContext ? SkToBool(shaderContext->getFlags() & SkShader::kOpaqueAlpha_Flag)
: 0xFF == paint.getAlpha();
}
struct State32 : SkXfermode::PM4fState {
typedef uint32_t DstType;
SkXfermode::PM4fProc1 fProc1;
SkXfermode::PM4fProcN fProcN;
SkPM4f fPM4f;
SkPM4f* fBuffer;
State32(const SkImageInfo& info, const SkPaint& paint, const SkShader::Context* shaderContext) {
fXfer = SkSafeRef(paint.getXfermode());
fFlags = 0;
if (is_opaque(paint, shaderContext)) {
fFlags |= SkXfermode::kSrcIsOpaque_PM4fFlag;
}
if (info.isSRGB()) {
fFlags |= SkXfermode::kDstIsSRGB_PM4fFlag;
}
if (fXfer) {
fProc1 = fXfer->getPM4fProc1(fFlags);
fProcN = fXfer->getPM4fProcN(fFlags);
} else {
fProc1 = SkXfermode::GetPM4fProc1(SkXfermode::kSrcOver_Mode, fFlags);
fProcN = SkXfermode::GetPM4fProcN(SkXfermode::kSrcOver_Mode, fFlags);
}
fBuffer = nullptr;
if (shaderContext) {
fBuffer = new SkPM4f[info.width()];
} else {
fPM4f = SkColor4f::FromColor(paint.getColor()).premul();
}
}
~State32() {
SkSafeUnref(fXfer);
delete[] fBuffer;
}
static DstType* WritableAddr(const SkPixmap& device, int x, int y) {
return device.writable_addr32(x, y);
}
};
struct State64 : SkXfermode::U64State {
typedef uint64_t DstType;
SkXfermode::U64Proc1 fProc1;
SkXfermode::U64ProcN fProcN;
SkPM4f fPM4f;
SkPM4f* fBuffer;
State64(const SkImageInfo& info, const SkPaint& paint, const SkShader::Context* shaderContext) {
fXfer = SkSafeRef(paint.getXfermode());
fFlags = 0;
if (is_opaque(paint, shaderContext)) {
fFlags |= SkXfermode::kSrcIsOpaque_PM4fFlag;
}
if (kRGBA_F16_SkColorType == info.colorType()) {
fFlags |= SkXfermode::kDstIsFloat16_U64Flag;
}
SkXfermode::Mode mode;
if (SkXfermode::AsMode(fXfer, &mode)) {
mode = SkXfermode::kSrcOver_Mode;
}
fProc1 = SkXfermode::GetU64Proc1(mode, fFlags);
fProcN = SkXfermode::GetU64ProcN(mode, fFlags);
fBuffer = nullptr;
if (shaderContext) {
fBuffer = new SkPM4f[info.width()];
} else {
fPM4f = SkColor4f::FromColor(paint.getColor()).premul();
}
}
~State64() {
SkSafeUnref(fXfer);
delete[] fBuffer;
}
static DstType* WritableAddr(const SkPixmap& device, int x, int y) {
return device.writable_addr64(x, y);
}
};
template <typename State> SkBlitter* create(const SkPixmap& device, const SkPaint& paint,
SkShader::Context* shaderContext,
SkTBlitterAllocator* allocator) {
SkASSERT(allocator != nullptr);
if (shaderContext) {
return allocator->createT<SkState_Shader_Blitter<State>>(device, paint, shaderContext);
} else {
SkColor color = paint.getColor();
if (0 == SkColorGetA(color)) {
return nullptr;
}
return allocator->createT<SkState_Blitter<State>>(device, paint);
}
}
SkBlitter* SkBlitter_ARGB32_Create(const SkPixmap& device, const SkPaint& paint,
SkShader::Context* shaderContext,
SkTBlitterAllocator* allocator) {
return create<State32>(device, paint, shaderContext, allocator);
}
SkBlitter* SkBlitter_ARGB64_Create(const SkPixmap& device, const SkPaint& paint,
SkShader::Context* shaderContext,
SkTBlitterAllocator* allocator) {
return create<State64>(device, paint, shaderContext, allocator);
}