add SkLerpXfermode

BUG=
R=bsalomon@google.com

Review URL: https://codereview.chromium.org/15602003

git-svn-id: http://skia.googlecode.com/svn/trunk@9229 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
reed@google.com 2013-05-21 21:33:11 +00:00
parent edef4aa8d8
commit b83cb9bf89
6 changed files with 238 additions and 10 deletions

64
gm/lerpmode.cpp Normal file
View File

@ -0,0 +1,64 @@
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "gm.h"
#include "SkCanvas.h"
#include "SkLerpXfermode.h"
static void show_circlelayers(SkCanvas* canvas, SkXfermode* mode) {
SkPaint paint;
paint.setAntiAlias(true);
SkRect r, bounds = { 10, 10, 110, 110 };
r = bounds;
r.fRight = bounds.centerX();
canvas->drawRect(r, paint);
canvas->saveLayer(&bounds, NULL);
paint.setColor(0x80FF0000);
r = bounds;
r.inset(20, 0);
canvas->drawOval(r, paint);
paint.setColor(0x800000FF);
r = bounds;
r.inset(0, 20);
paint.setXfermode(mode);
canvas->drawOval(r, paint);
canvas->restore();
}
class LerpXfermodeGM : public skiagm::GM {
public:
LerpXfermodeGM() {}
protected:
virtual SkString onShortName() SK_OVERRIDE {
return SkString("lerpmode");
}
virtual SkISize onISize() SK_OVERRIDE {
return SkISize::Make(240, 120);
}
virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
show_circlelayers(canvas, NULL);
canvas->translate(150, 0);
SkAutoTUnref<SkXfermode> mode(SkLerpXfermode::Create(0.5f));
show_circlelayers(canvas, mode.get());
}
private:
typedef skiagm::GM INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
DEF_GM( return SkNEW(LerpXfermodeGM); )

View File

@ -34,6 +34,7 @@
'<(skia_src_path)/effects/SkKernel33MaskFilter.cpp',
'<(skia_src_path)/effects/SkLayerDrawLooper.cpp',
'<(skia_src_path)/effects/SkLayerRasterizer.cpp',
'<(skia_src_path)/effects/SkLerpXfermode.cpp',
'<(skia_src_path)/effects/SkLightingImageFilter.cpp',
'<(skia_src_path)/effects/SkMatrixConvolutionImageFilter.cpp',
'<(skia_src_path)/effects/SkMergeImageFilter.cpp',
@ -91,6 +92,7 @@
'<(skia_include_path)/effects/SkKernel33MaskFilter.h',
'<(skia_include_path)/effects/SkLayerDrawLooper.h',
'<(skia_include_path)/effects/SkLayerRasterizer.h',
'<(skia_include_path)/effects/SkLerpXfermode.h',
'<(skia_include_path)/effects/SkLightingImageFilter.h',
'<(skia_include_path)/effects/SkOffsetImageFilter.h',
'<(skia_include_path)/effects/SkMorphologyImageFilter.h',

View File

@ -49,6 +49,7 @@
'../gm/hittestpath.cpp',
'../gm/imageblur.cpp',
'../gm/imagemagnifier.cpp',
'../gm/lerpmode.cpp',
'../gm/lighting.cpp',
'../src/image/SkImage_Codec.cpp',
'../gm/image.cpp',

View File

@ -273,16 +273,16 @@ static inline SkPMColor SkFourByteInterp(SkPMColor src, SkPMColor dst,
* architectures than an equivalent 64b version and 30% faster than
* SkFourByteInterp(). Third parameter controls blending of the first two:
* (src, dst, 0) returns dst
* (src, dst, 0xFF) returns src
* ** Does not match the results of SkFourByteInterp() because we use
* (src, dst, 256) returns src
* ** Does not match the results of SkFourByteInterp256() because we use
* a more accurate scale computation!
* TODO: migrate Skia function to using an accurate 255->266 alpha
* conversion.
*/
static inline SkPMColor SkFastFourByteInterp(SkPMColor src,
SkPMColor dst,
U8CPU srcWeight) {
SkASSERT(srcWeight < 256);
static inline SkPMColor SkFastFourByteInterp256(SkPMColor src,
SkPMColor dst,
unsigned scale) {
SkASSERT(scale <= 256);
// Reorders ARGB to AG-RB in order to reduce the number of operations.
const uint32_t mask = 0xFF00FF;
@ -291,16 +291,21 @@ static inline SkPMColor SkFastFourByteInterp(SkPMColor src,
uint32_t dst_rb = dst & mask;
uint32_t dst_ag = (dst >> 8) & mask;
// scale = srcWeight + (srcWeight >> 7) is more accurate than
// scale = srcWeight + 1, but 7% slower
int scale = srcWeight + (srcWeight >> 7);
uint32_t ret_rb = src_rb * scale + (256 - scale) * dst_rb;
uint32_t ret_ag = src_ag * scale + (256 - scale) * dst_ag;
return (ret_ag & ~mask) | ((ret_rb & ~mask) >> 8);
}
static inline SkPMColor SkFastFourByteInterp(SkPMColor src,
SkPMColor dst,
U8CPU srcWeight) {
SkASSERT(srcWeight <= 255);
// scale = srcWeight + (srcWeight >> 7) is more accurate than
// scale = srcWeight + 1, but 7% slower
return SkFastFourByteInterp256(src, dst, srcWeight + (srcWeight >> 7));
}
/**
* Same as SkPackARGB32, but this version guarantees to not check that the
* values are premultiplied in the debug version.

View File

@ -0,0 +1,46 @@
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkLerpXfermode_DEFINED
#define SkLerpXfermode_DEFINED
#include "SkXfermode.h"
class SK_API SkLerpXfermode : public SkXfermode {
public:
/**
* result = scale * src + (1 - scale) * dst
*
* When scale == 1, this is the same as kSrc_Mode
* When scale == 0, this is the same as kDst_Mode
*/
static SkXfermode* Create(SkScalar scale);
// overrides from SkXfermode
virtual void xfer32(SkPMColor dst[], const SkPMColor src[], int count,
const SkAlpha aa[]) const SK_OVERRIDE;
virtual void xfer16(uint16_t dst[], const SkPMColor src[], int count,
const SkAlpha aa[]) const SK_OVERRIDE;
virtual void xferA8(SkAlpha dst[], const SkPMColor src[], int count,
const SkAlpha aa[]) const SK_OVERRIDE;
SK_DEVELOPER_TO_STRING()
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkLerpXfermode)
protected:
SkLerpXfermode(SkFlattenableReadBuffer&);
virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
private:
SkLerpXfermode(unsigned scale256);
unsigned fScale256; // 0..256
typedef SkXfermode INHERITED;
};
#endif

View File

@ -0,0 +1,110 @@
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkLerpXfermode.h"
#include "SkColorPriv.h"
#include "SkFlattenableBuffers.h"
#include "SkString.h"
SkXfermode* SkLerpXfermode::Create(SkScalar scale) {
int scale256 = SkScalarRoundToInt(scale * 256);
if (scale256 >= 256) {
return SkXfermode::Create(SkXfermode::kSrc_Mode);
} else if (scale256 <= 0) {
return SkXfermode::Create(SkXfermode::kDst_Mode);
}
return SkNEW_ARGS(SkLerpXfermode, (scale256));
}
SkLerpXfermode::SkLerpXfermode(unsigned scale256) : fScale256(scale256) {}
SkLerpXfermode::SkLerpXfermode(SkFlattenableReadBuffer& buffer)
: INHERITED(buffer) {
fScale256 = buffer.readUInt();
}
void SkLerpXfermode::flatten(SkFlattenableWriteBuffer& buffer) const {
this->INHERITED::flatten(buffer);
buffer.writeUInt(fScale256);
}
void SkLerpXfermode::xfer32(SkPMColor dst[], const SkPMColor src[], int count,
const SkAlpha aa[]) const {
const int scale = fScale256;
if (aa) {
for (int i = 0; i < count; ++i) {
unsigned a = aa[i];
if (a) {
SkPMColor dstC = dst[i];
SkPMColor resC = SkFastFourByteInterp256(src[i], dstC, scale);
if (a < 255) {
resC = SkFastFourByteInterp256(resC, dstC, a + (a >> 7));
}
dst[i] = resC;
}
}
} else {
for (int i = 0; i < count; ++i) {
dst[i] = SkFastFourByteInterp256(src[i], dst[i], scale);
}
}
}
void SkLerpXfermode::xfer16(uint16_t dst[], const SkPMColor src[], int count,
const SkAlpha aa[]) const {
const int scale = fScale256;
if (aa) {
for (int i = 0; i < count; ++i) {
unsigned a = aa[i];
if (a) {
SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
SkPMColor resC = SkFastFourByteInterp256(src[i], dstC, scale);
if (a < 255) {
resC = SkFastFourByteInterp256(resC, dstC, a + (a >> 7));
}
dst[i] = SkPixel32ToPixel16(resC);
}
}
} else {
for (int i = 0; i < count; ++i) {
SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
SkPMColor resC = SkFastFourByteInterp256(src[i], dstC, scale);
dst[i] = SkPixel32ToPixel16(resC);
}
}
}
void SkLerpXfermode::xferA8(SkAlpha dst[], const SkPMColor src[], int count,
const SkAlpha aa[]) const {
const int scale = fScale256;
if (aa) {
for (int i = 0; i < count; ++i) {
unsigned a = aa[i];
if (a) {
unsigned dstA = dst[i];
unsigned resA = SkAlphaBlend(SkGetPackedA32(src[i]), dstA, scale);
if (a < 255) {
resA = SkAlphaBlend(resA, dstA, a + (a >> 7));
}
dst[i] = resA;
}
}
} else {
for (int i = 0; i < count; ++i) {
dst[i] = SkAlphaBlend(SkGetPackedA32(src[i]), dst[i], scale);
}
}
}
#ifdef SK_DEVELOPER
void SkLerpXfermode::toString(SkString* str) const {
str->printf("SkLerpXfermode: scale: %g", fScale256 / 256.0);
}
#endif