--- /dev/null
+/*
+ * 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); )
+
'<(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',
'<(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',
'../gm/hittestpath.cpp',
'../gm/imageblur.cpp',
'../gm/imagemagnifier.cpp',
+ '../gm/lerpmode.cpp',
'../gm/lighting.cpp',
'../src/image/SkImage_Codec.cpp',
'../gm/image.cpp',
* 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;
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.
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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