aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkXfermode.cpp
diff options
context:
space:
mode:
authorGravatar reed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2008-12-17 15:59:43 +0000
committerGravatar reed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2008-12-17 15:59:43 +0000
commit8a1c16ff38322f0210116fa7293eb8817c7e477e (patch)
treefe40e07f6c8983318a2f79032b9a706ede1090c1 /src/core/SkXfermode.cpp
parent2559c629078f738ac37095d896d580b681ac6a30 (diff)
grab from latest android
git-svn-id: http://skia.googlecode.com/svn/trunk@27 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/core/SkXfermode.cpp')
-rw-r--r--src/core/SkXfermode.cpp978
1 files changed, 978 insertions, 0 deletions
diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp
new file mode 100644
index 0000000000..e8a202dc08
--- /dev/null
+++ b/src/core/SkXfermode.cpp
@@ -0,0 +1,978 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SkXfermode.h"
+#include "SkColorPriv.h"
+
+#define SkAlphaMulAlpha(a, b) SkMulDiv255Round(a, b)
+
+static SkPMColor SkFourByteInterp(SkPMColor src, SkPMColor dst, U8CPU alpha) {
+ unsigned scale = SkAlpha255To256(alpha);
+
+ unsigned a = SkAlphaBlend(SkGetPackedA32(src), SkGetPackedA32(dst), scale);
+ unsigned r = SkAlphaBlend(SkGetPackedR32(src), SkGetPackedR32(dst), scale);
+ unsigned g = SkAlphaBlend(SkGetPackedG32(src), SkGetPackedG32(dst), scale);
+ unsigned b = SkAlphaBlend(SkGetPackedB32(src), SkGetPackedB32(dst), scale);
+
+ return SkPackARGB32(a, r, g, b);
+}
+
+// idea for higher precision blends in xfer procs (and slightly faster)
+// see DstATop as a probable caller
+static U8CPU mulmuldiv255round(U8CPU a, U8CPU b, U8CPU c, U8CPU d) {
+ SkASSERT(a <= 255);
+ SkASSERT(b <= 255);
+ SkASSERT(c <= 255);
+ SkASSERT(d <= 255);
+ unsigned prod = SkMulS16(a, b) + SkMulS16(c, d) + 128;
+ unsigned result = (prod + (prod >> 8)) >> 8;
+ SkASSERT(result <= 255);
+ return result;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool SkXfermode::asCoeff(Coeff* src, Coeff* dst) {
+ return false;
+}
+
+SkPMColor SkXfermode::xferColor(SkPMColor src, SkPMColor dst) {
+ // no-op. subclasses should override this
+ return dst;
+}
+
+void SkXfermode::xfer32(SK_RESTRICT SkPMColor dst[],
+ const SK_RESTRICT SkPMColor src[], int count,
+ const SK_RESTRICT SkAlpha aa[]) {
+ SkASSERT(dst && src && count >= 0);
+
+ if (NULL == aa) {
+ for (int i = count - 1; i >= 0; --i) {
+ dst[i] = this->xferColor(src[i], dst[i]);
+ }
+ } else {
+ for (int i = count - 1; i >= 0; --i) {
+ unsigned a = aa[i];
+ if (0 != a) {
+ SkPMColor dstC = dst[i];
+ SkPMColor C = this->xferColor(src[i], dstC);
+ if (0xFF != a) {
+ C = SkFourByteInterp(C, dstC, a);
+ }
+ dst[i] = C;
+ }
+ }
+ }
+}
+
+void SkXfermode::xfer16(SK_RESTRICT uint16_t dst[],
+ const SK_RESTRICT SkPMColor src[], int count,
+ const SK_RESTRICT SkAlpha aa[]) {
+ SkASSERT(dst && src && count >= 0);
+
+ if (NULL == aa) {
+ for (int i = count - 1; i >= 0; --i) {
+ SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
+ dst[i] = SkPixel32ToPixel16_ToU16(this->xferColor(src[i], dstC));
+ }
+ } else {
+ for (int i = count - 1; i >= 0; --i) {
+ unsigned a = aa[i];
+ if (0 != a) {
+ SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
+ SkPMColor C = this->xferColor(src[i], dstC);
+ if (0xFF != a) {
+ C = SkFourByteInterp(C, dstC, a);
+ }
+ dst[i] = SkPixel32ToPixel16_ToU16(C);
+ }
+ }
+ }
+}
+
+void SkXfermode::xfer4444(SK_RESTRICT SkPMColor16 dst[],
+ const SK_RESTRICT SkPMColor src[], int count,
+ const SK_RESTRICT SkAlpha aa[])
+{
+ SkASSERT(dst && src && count >= 0);
+
+ if (NULL == aa) {
+ for (int i = count - 1; i >= 0; --i) {
+ SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
+ dst[i] = SkPixel32ToPixel4444(this->xferColor(src[i], dstC));
+ }
+ } else {
+ for (int i = count - 1; i >= 0; --i) {
+ unsigned a = aa[i];
+ if (0 != a) {
+ SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
+ SkPMColor C = this->xferColor(src[i], dstC);
+ if (0xFF != a) {
+ C = SkFourByteInterp(C, dstC, a);
+ }
+ dst[i] = SkPixel32ToPixel4444(C);
+ }
+ }
+ }
+}
+
+void SkXfermode::xferA8(SK_RESTRICT SkAlpha dst[],
+ const SkPMColor src[], int count,
+ const SK_RESTRICT SkAlpha aa[])
+{
+ SkASSERT(dst && src && count >= 0);
+
+ if (NULL == aa) {
+ for (int i = count - 1; i >= 0; --i) {
+ SkPMColor res = this->xferColor(src[i], (dst[i] << SK_A32_SHIFT));
+ dst[i] = SkToU8(SkGetPackedA32(res));
+ }
+ } else {
+ for (int i = count - 1; i >= 0; --i) {
+ unsigned a = aa[i];
+ if (0 != a) {
+ SkAlpha dstA = dst[i];
+ unsigned A = SkGetPackedA32(this->xferColor(src[i],
+ (SkPMColor)(dstA << SK_A32_SHIFT)));
+ if (0xFF != a) {
+ A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
+ }
+ dst[i] = SkToU8(A);
+ }
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SkProcXfermode::xfer32(SK_RESTRICT SkPMColor dst[],
+ const SK_RESTRICT SkPMColor src[], int count,
+ const SK_RESTRICT SkAlpha aa[]) {
+ SkASSERT(dst && src && count >= 0);
+
+ SkXfermodeProc proc = fProc;
+
+ if (NULL != proc) {
+ if (NULL == aa) {
+ for (int i = count - 1; i >= 0; --i) {
+ dst[i] = proc(src[i], dst[i]);
+ }
+ } else {
+ for (int i = count - 1; i >= 0; --i) {
+ unsigned a = aa[i];
+ if (0 != a) {
+ SkPMColor dstC = dst[i];
+ SkPMColor C = proc(src[i], dstC);
+ if (a != 0xFF) {
+ C = SkFourByteInterp(C, dstC, a);
+ }
+ dst[i] = C;
+ }
+ }
+ }
+ }
+}
+
+void SkProcXfermode::xfer16(SK_RESTRICT uint16_t dst[],
+ const SK_RESTRICT SkPMColor src[], int count,
+ const SK_RESTRICT SkAlpha aa[]) {
+ SkASSERT(dst && src && count >= 0);
+
+ SkXfermodeProc proc = fProc;
+
+ if (NULL != proc) {
+ if (NULL == aa) {
+ for (int i = count - 1; i >= 0; --i) {
+ SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
+ dst[i] = SkPixel32ToPixel16_ToU16(proc(src[i], dstC));
+ }
+ } else {
+ for (int i = count - 1; i >= 0; --i) {
+ unsigned a = aa[i];
+ if (0 != a) {
+ SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
+ SkPMColor C = proc(src[i], dstC);
+ if (0xFF != a) {
+ C = SkFourByteInterp(C, dstC, a);
+ }
+ dst[i] = SkPixel32ToPixel16_ToU16(C);
+ }
+ }
+ }
+ }
+}
+
+void SkProcXfermode::xfer4444(SK_RESTRICT SkPMColor16 dst[],
+ const SK_RESTRICT SkPMColor src[], int count,
+ const SK_RESTRICT SkAlpha aa[]) {
+ SkASSERT(dst && src && count >= 0);
+
+ SkXfermodeProc proc = fProc;
+
+ if (NULL != proc) {
+ if (NULL == aa) {
+ for (int i = count - 1; i >= 0; --i) {
+ SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
+ dst[i] = SkPixel32ToPixel4444(proc(src[i], dstC));
+ }
+ } else {
+ for (int i = count - 1; i >= 0; --i) {
+ unsigned a = aa[i];
+ if (0 != a) {
+ SkPMColor dstC = SkPixel4444ToPixel32(dst[i]);
+ SkPMColor C = proc(src[i], dstC);
+ if (0xFF != a) {
+ C = SkFourByteInterp(C, dstC, a);
+ }
+ dst[i] = SkPixel32ToPixel4444(C);
+ }
+ }
+ }
+ }
+}
+
+void SkProcXfermode::xferA8(SK_RESTRICT SkAlpha dst[],
+ const SK_RESTRICT SkPMColor src[], int count,
+ const SK_RESTRICT SkAlpha aa[]) {
+ SkASSERT(dst && src && count >= 0);
+
+ SkXfermodeProc proc = fProc;
+
+ if (NULL != proc) {
+ if (NULL == aa) {
+ for (int i = count - 1; i >= 0; --i) {
+ SkPMColor res = proc(src[i], dst[i] << SK_A32_SHIFT);
+ dst[i] = SkToU8(SkGetPackedA32(res));
+ }
+ } else {
+ for (int i = count - 1; i >= 0; --i) {
+ unsigned a = aa[i];
+ if (0 != a) {
+ SkAlpha dstA = dst[i];
+ SkPMColor res = proc(src[i], dstA << SK_A32_SHIFT);
+ unsigned A = SkGetPackedA32(res);
+ if (0xFF != a) {
+ A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
+ }
+ dst[i] = SkToU8(A);
+ }
+ }
+ }
+ }
+}
+
+SkProcXfermode::SkProcXfermode(SkFlattenableReadBuffer& buffer)
+ : SkXfermode(buffer) {
+ fProc = (SkXfermodeProc)buffer.readFunctionPtr();
+}
+
+void SkProcXfermode::flatten(SkFlattenableWriteBuffer& buffer) {
+ buffer.writeFunctionPtr((void*)fProc);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+class SkProcCoeffXfermode : public SkProcXfermode {
+public:
+ SkProcCoeffXfermode(SkXfermodeProc proc, Coeff sc, Coeff dc)
+ : INHERITED(proc), fSrcCoeff(sc), fDstCoeff(dc) {
+ }
+
+ virtual bool asCoeff(Coeff* sc, Coeff* dc) {
+ if (sc) {
+ *sc = fSrcCoeff;
+ }
+ if (dc) {
+ *dc = fDstCoeff;
+ }
+ return true;
+ }
+
+ virtual Factory getFactory() { return CreateProc; }
+ virtual void flatten(SkFlattenableWriteBuffer& buffer) {
+ this->INHERITED::flatten(buffer);
+ buffer.write32(fSrcCoeff);
+ buffer.write32(fDstCoeff);
+ }
+
+protected:
+ SkProcCoeffXfermode(SkFlattenableReadBuffer& buffer)
+ : INHERITED(buffer) {
+ fSrcCoeff = (Coeff)buffer.readU32();
+ fDstCoeff = (Coeff)buffer.readU32();
+ }
+
+private:
+ Coeff fSrcCoeff, fDstCoeff;
+
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+ return SkNEW_ARGS(SkProcCoeffXfermode, (buffer)); }
+
+ typedef SkProcXfermode INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+// kClear_Mode, //!< [0, 0]
+static SkPMColor clear_modeproc(SkPMColor src, SkPMColor dst) {
+ return 0;
+}
+
+// kSrc_Mode, //!< [Sa, Sc]
+static SkPMColor src_modeproc(SkPMColor src, SkPMColor dst) {
+ return src;
+}
+
+// kDst_Mode, //!< [Da, Dc]
+static SkPMColor dst_modeproc(SkPMColor src, SkPMColor dst) {
+ return dst;
+}
+
+// kSrcOver_Mode, //!< [Sa + (1 - Sa)*Da, Sc + (1 - Sa)*Dc]
+static SkPMColor srcover_modeproc(SkPMColor src, SkPMColor dst) {
+ return src + SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
+}
+
+// kDstOver_Mode, //!< [Sa + (1 - Sa)*Da, Dc + (1 - Da)*Sc]
+static SkPMColor dstover_modeproc(SkPMColor src, SkPMColor dst) {
+ unsigned sa = SkGetPackedA32(src);
+ unsigned da = SkGetPackedA32(dst);
+ unsigned ida = 255 - da;
+
+ return SkPackARGB32(sa + da - SkAlphaMulAlpha(sa, da),
+ SkGetPackedR32(dst) + SkAlphaMulAlpha(ida, SkGetPackedR32(src)),
+ SkGetPackedG32(dst) + SkAlphaMulAlpha(ida, SkGetPackedG32(src)),
+ SkGetPackedB32(dst) + SkAlphaMulAlpha(ida, SkGetPackedB32(src)));
+}
+
+// kSrcIn_Mode, //!< [Sa * Da, Sc * Da]
+static SkPMColor srcin_modeproc(SkPMColor src, SkPMColor dst) {
+ return SkAlphaMulQ(src, SkAlpha255To256(SkGetPackedA32(dst)));
+}
+
+// kDstIn_Mode, //!< [Sa * Da, Sa * Dc]
+static SkPMColor dstin_modeproc(SkPMColor src, SkPMColor dst) {
+ return SkAlphaMulQ(dst, SkAlpha255To256(SkGetPackedA32(src)));
+}
+
+// kSrcOut_Mode, //!< [Sa * (1 - Da), Sc * (1 - Da)]
+static SkPMColor srcout_modeproc(SkPMColor src, SkPMColor dst) {
+ return SkAlphaMulQ(src, SkAlpha255To256(255 - SkGetPackedA32(dst)));
+}
+
+// kDstOut_Mode, //!< [Da * (1 - Sa), Dc * (1 - Sa)]
+static SkPMColor dstout_modeproc(SkPMColor src, SkPMColor dst) {
+ return SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
+}
+
+// kSrcATop_Mode, //!< [Da, Sc * Da + (1 - Sa) * Dc]
+static SkPMColor srcatop_modeproc(SkPMColor src, SkPMColor dst) {
+ unsigned sa = SkGetPackedA32(src);
+ unsigned da = SkGetPackedA32(dst);
+ unsigned isa = 255 - sa;
+
+ return SkPackARGB32(da,
+ SkAlphaMulAlpha(da, SkGetPackedR32(src)) +
+ SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
+ SkAlphaMulAlpha(da, SkGetPackedG32(src)) +
+ SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
+ SkAlphaMulAlpha(da, SkGetPackedB32(src)) +
+ SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
+}
+
+// kDstATop_Mode, //!< [Sa, Sa * Dc + Sc * (1 - Da)]
+static SkPMColor dstatop_modeproc(SkPMColor src, SkPMColor dst) {
+ unsigned sa = SkGetPackedA32(src);
+ unsigned da = SkGetPackedA32(dst);
+ unsigned ida = 255 - da;
+
+ return SkPackARGB32(sa,
+ SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
+ SkAlphaMulAlpha(sa, SkGetPackedR32(dst)),
+ SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
+ SkAlphaMulAlpha(sa, SkGetPackedG32(dst)),
+ SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
+ SkAlphaMulAlpha(sa, SkGetPackedB32(dst)));
+}
+
+// kXor_Mode [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]
+static SkPMColor xor_modeproc(SkPMColor src, SkPMColor dst) {
+ unsigned sa = SkGetPackedA32(src);
+ unsigned da = SkGetPackedA32(dst);
+ unsigned isa = 255 - sa;
+ unsigned ida = 255 - da;
+
+ return SkPackARGB32(sa + da - (SkAlphaMulAlpha(sa, da) << 1),
+ SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
+ SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
+ SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
+ SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
+ SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
+ SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
+}
+
+
+// kDarken_Mode, [Sa + Da - Sa·Da, Sc·(1 - Da) + Dc·(1 - Sa) + min(Sc, Dc)]
+
+static inline unsigned darken_p(unsigned src, unsigned dst,
+ unsigned src_mul, unsigned dst_mul) {
+ return ((dst_mul * src + src_mul * dst) >> 8) + SkMin32(src, dst);
+}
+
+static SkPMColor darken_modeproc(SkPMColor src, SkPMColor dst) {
+ unsigned sa = SkGetPackedA32(src);
+ unsigned da = SkGetPackedA32(dst);
+ unsigned src_scale = SkAlpha255To256(255 - sa);
+ unsigned dst_scale = SkAlpha255To256(255 - da);
+
+ unsigned ra = sa + da - SkAlphaMulAlpha(sa, da);
+ unsigned rr = darken_p(SkGetPackedR32(src), SkGetPackedR32(dst),
+ src_scale, dst_scale);
+ unsigned rg = darken_p(SkGetPackedG32(src), SkGetPackedG32(dst),
+ src_scale, dst_scale);
+ unsigned rb = darken_p(SkGetPackedB32(src), SkGetPackedB32(dst),
+ src_scale, dst_scale);
+
+ return SkPackARGB32(ra, SkFastMin32(rr, ra),
+ SkFastMin32(rg, ra), SkFastMin32(rb, ra));
+}
+
+// kLighten_Mode, [Sa + Da - Sa·Da, Sc·(1 - Da) + Dc·(1 - Sa) + max(Sc, Dc)]
+static inline unsigned lighten_p(unsigned src, unsigned dst,
+ unsigned src_mul, unsigned dst_mul) {
+ return ((dst_mul * src + src_mul * dst) >> 8) + SkMax32(src, dst);
+}
+
+static SkPMColor lighten_modeproc(SkPMColor src, SkPMColor dst) {
+ unsigned sa = SkGetPackedA32(src);
+ unsigned da = SkGetPackedA32(dst);
+ unsigned src_scale = SkAlpha255To256(255 - sa);
+ unsigned dst_scale = SkAlpha255To256(255 - da);
+
+ unsigned ra = sa + da - SkAlphaMulAlpha(sa, da);
+ unsigned rr = lighten_p(SkGetPackedR32(src), SkGetPackedR32(dst),
+ src_scale, dst_scale);
+ unsigned rg = lighten_p(SkGetPackedG32(src), SkGetPackedG32(dst),
+ src_scale, dst_scale);
+ unsigned rb = lighten_p(SkGetPackedB32(src), SkGetPackedB32(dst),
+ src_scale, dst_scale);
+
+ return SkPackARGB32(ra, SkFastMin32(rr, ra),
+ SkFastMin32(rg, ra), SkFastMin32(rb, ra));
+}
+
+static SkPMColor mult_modeproc(SkPMColor src, SkPMColor dst) {
+ int a = SkAlphaMulAlpha(SkGetPackedA32(src), SkGetPackedA32(dst));
+ int r = SkAlphaMulAlpha(SkGetPackedR32(src), SkGetPackedR32(dst));
+ int g = SkAlphaMulAlpha(SkGetPackedG32(src), SkGetPackedG32(dst));
+ int b = SkAlphaMulAlpha(SkGetPackedB32(src), SkGetPackedB32(dst));
+ return SkPackARGB32(a, r, g, b);
+}
+
+static inline int screen_byte(int a, int b) {
+ return a + b - SkAlphaMulAlpha(a, b);
+}
+
+static SkPMColor screen_modeproc(SkPMColor src, SkPMColor dst) {
+ int a = screen_byte(SkGetPackedA32(src), SkGetPackedA32(dst));
+ int r = screen_byte(SkGetPackedR32(src), SkGetPackedR32(dst));
+ int g = screen_byte(SkGetPackedG32(src), SkGetPackedG32(dst));
+ int b = screen_byte(SkGetPackedB32(src), SkGetPackedB32(dst));
+ return SkPackARGB32(a, r, g, b);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+class SkClearXfermode : public SkProcCoeffXfermode {
+public:
+ SkClearXfermode() : SkProcCoeffXfermode(clear_modeproc,
+ kZero_Coeff, kZero_Coeff) {}
+
+ virtual void xfer32(SK_RESTRICT SkPMColor dst[],
+ const SK_RESTRICT SkPMColor[], int count,
+ const SK_RESTRICT SkAlpha aa[]) {
+ SkASSERT(dst && count >= 0);
+
+ if (NULL == aa) {
+ memset(dst, 0, count << 2);
+ } else {
+ for (int i = count - 1; i >= 0; --i) {
+ unsigned a = aa[i];
+ if (0xFF == a) {
+ dst[i] = 0;
+ } else if (a != 0) {
+ dst[i] = SkAlphaMulQ(dst[i], SkAlpha255To256(255 - a));
+ }
+ }
+ }
+ }
+ virtual void xferA8(SK_RESTRICT SkAlpha dst[],
+ const SK_RESTRICT SkPMColor[], int count,
+ const SK_RESTRICT SkAlpha aa[]) {
+ SkASSERT(dst && count >= 0);
+
+ if (NULL == aa) {
+ memset(dst, 0, count);
+ } else {
+ for (int i = count - 1; i >= 0; --i) {
+ unsigned a = aa[i];
+ if (0xFF == a) {
+ dst[i] = 0;
+ } else if (0 != a) {
+ dst[i] = SkAlphaMulAlpha(dst[i], 255 - a);
+ }
+ }
+ }
+ }
+
+ virtual Factory getFactory() { return CreateProc; }
+
+private:
+ SkClearXfermode(SkFlattenableReadBuffer& buffer)
+ : SkProcCoeffXfermode(buffer) {}
+
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+ return SkNEW_ARGS(SkClearXfermode, (buffer));
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class SkSrcXfermode : public SkProcCoeffXfermode {
+public:
+ SkSrcXfermode() : SkProcCoeffXfermode(src_modeproc,
+ kOne_Coeff, kZero_Coeff) {}
+
+ virtual void xfer32(SK_RESTRICT SkPMColor dst[],
+ const SK_RESTRICT SkPMColor src[], int count,
+ const SK_RESTRICT SkAlpha aa[]) {
+ SkASSERT(dst && src && count >= 0);
+
+ if (NULL == aa) {
+ memcpy(dst, src, count << 2);
+ } else {
+ for (int i = count - 1; i >= 0; --i) {
+ unsigned a = aa[i];
+ if (a == 0xFF) {
+ dst[i] = src[i];
+ } else if (a != 0) {
+ dst[i] = SkFourByteInterp(src[i], dst[i], a);
+ }
+ }
+ }
+ }
+
+ virtual void xferA8(SK_RESTRICT SkAlpha dst[],
+ const SK_RESTRICT SkPMColor src[], int count,
+ const SK_RESTRICT SkAlpha aa[]) {
+ SkASSERT(dst && src && count >= 0);
+
+ if (NULL == aa) {
+ for (int i = count - 1; i >= 0; --i) {
+ dst[i] = SkToU8(SkGetPackedA32(src[i]));
+ }
+ } else {
+ for (int i = count - 1; i >= 0; --i) {
+ unsigned a = aa[i];
+ if (0 != a) {
+ unsigned srcA = SkGetPackedA32(src[i]);
+ if (a == 0xFF) {
+ dst[i] = SkToU8(srcA);
+ } else {
+ dst[i] = SkToU8(SkAlphaBlend(srcA, dst[i], a));
+ }
+ }
+ }
+ }
+ }
+
+ virtual Factory getFactory() { return CreateProc; }
+
+private:
+ SkSrcXfermode(SkFlattenableReadBuffer& buffer)
+ : SkProcCoeffXfermode(buffer) {}
+
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+ return SkNEW_ARGS(SkSrcXfermode, (buffer));
+ }
+};
+
+class SkDstInXfermode : public SkProcCoeffXfermode {
+public:
+ SkDstInXfermode() : SkProcCoeffXfermode(dstin_modeproc,
+ kZero_Coeff, kSA_Coeff) {}
+
+ virtual void xfer32(SK_RESTRICT SkPMColor dst[],
+ const SK_RESTRICT SkPMColor src[], int count,
+ const SK_RESTRICT SkAlpha aa[]) {
+ SkASSERT(dst && src);
+
+ if (count <= 0) {
+ return;
+ }
+ if (NULL != aa) {
+ return this->INHERITED::xfer32(dst, src, count, aa);
+ }
+
+ do {
+ unsigned a = SkGetPackedA32(*src);
+ *dst = SkAlphaMulQ(*dst, SkAlpha255To256(a));
+ dst++;
+ src++;
+ } while (--count != 0);
+ }
+
+ virtual Factory getFactory() { return CreateProc; }
+
+private:
+ SkDstInXfermode(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
+
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+ return SkNEW_ARGS(SkDstInXfermode, (buffer));
+ }
+
+ typedef SkProcCoeffXfermode INHERITED;
+};
+
+class SkDstOutXfermode : public SkProcCoeffXfermode {
+public:
+ SkDstOutXfermode() : SkProcCoeffXfermode(dstout_modeproc,
+ kZero_Coeff, kISA_Coeff) {}
+
+ virtual void xfer32(SK_RESTRICT SkPMColor dst[],
+ const SK_RESTRICT SkPMColor src[], int count,
+ const SK_RESTRICT SkAlpha aa[]) {
+ SkASSERT(dst && src);
+
+ if (count <= 0) {
+ return;
+ }
+ if (NULL != aa) {
+ return this->INHERITED::xfer32(dst, src, count, aa);
+ }
+
+ do {
+ unsigned a = SkGetPackedA32(*src);
+ *dst = SkAlphaMulQ(*dst, SkAlpha255To256(255 - a));
+ dst++;
+ src++;
+ } while (--count != 0);
+ }
+
+ virtual Factory getFactory() { return CreateProc; }
+
+private:
+ SkDstOutXfermode(SkFlattenableReadBuffer& buffer)
+ : INHERITED(buffer) {}
+
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+ return SkNEW_ARGS(SkDstOutXfermode, (buffer));
+ }
+
+ typedef SkProcCoeffXfermode INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+#include "SkPorterDuff.h"
+
+struct ProcCoeff {
+ SkXfermodeProc fProc;
+ SkXfermode::Coeff fSC;
+ SkXfermode::Coeff fDC;
+};
+
+static const ProcCoeff gProcCoeffs[] = {
+ { clear_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kZero_Coeff },
+ { src_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kZero_Coeff },
+ { dst_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kOne_Coeff },
+ { srcover_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kISA_Coeff },
+ { dstover_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kOne_Coeff },
+ { srcin_modeproc, SkXfermode::kDA_Coeff, SkXfermode::kZero_Coeff },
+ { dstin_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kSA_Coeff },
+ { srcout_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kZero_Coeff },
+ { dstout_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kISA_Coeff },
+ { srcatop_modeproc, SkXfermode::kDA_Coeff, SkXfermode::kISA_Coeff },
+ { dstatop_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kSA_Coeff },
+ { xor_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kISA_Coeff },
+ // these two can't be represented as coefficients
+ { darken_modeproc, SkXfermode::Coeff(-1), SkXfermode::Coeff(-1) },
+ { lighten_modeproc, SkXfermode::Coeff(-1), SkXfermode::Coeff(-1) },
+ // these can use coefficients
+ { mult_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kSC_Coeff },
+ { screen_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kISC_Coeff }
+};
+
+SkXfermode* SkPorterDuff::CreateXfermode(SkPorterDuff::Mode mode) {
+ SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == SkPorterDuff::kModeCount);
+ SkASSERT((unsigned)mode < SkPorterDuff::kModeCount);
+
+ switch (mode) {
+ case kClear_Mode:
+ return SkNEW(SkClearXfermode);
+ case kSrc_Mode:
+ return SkNEW(SkSrcXfermode);
+ case kSrcOver_Mode:
+ return NULL;
+ case kDstIn_Mode:
+ return SkNEW(SkDstInXfermode);
+ case kDstOut_Mode:
+ return SkNEW(SkDstOutXfermode);
+ // these two can't be represented with Coeff
+ case kDarken_Mode:
+ return SkNEW_ARGS(SkProcXfermode, (darken_modeproc));
+ case kLighten_Mode:
+ return SkNEW_ARGS(SkProcXfermode, (lighten_modeproc));
+ // use the table
+ default: {
+ const ProcCoeff& rec = gProcCoeffs[mode];
+ SkASSERT((unsigned)rec.fSC < SkXfermode::kCoeffCount);
+ SkASSERT((unsigned)rec.fDC < SkXfermode::kCoeffCount);
+ return SkNEW_ARGS(SkProcCoeffXfermode, (rec.fProc,
+ rec.fSC, rec.fDC));
+ }
+ }
+}
+
+bool SkPorterDuff::IsMode(SkXfermode* xfer, Mode* mode) {
+ if (NULL == xfer) {
+ if (mode) {
+ *mode = kSrcOver_Mode;
+ }
+ return true;
+ }
+
+ SkXfermode::Coeff sc, dc;
+ if (xfer->asCoeff(&sc, &dc)) {
+ SkASSERT((unsigned)sc < (unsigned)SkXfermode::kCoeffCount);
+ SkASSERT((unsigned)dc < (unsigned)SkXfermode::kCoeffCount);
+
+ const ProcCoeff* rec = gProcCoeffs;
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gProcCoeffs); i++) {
+ if (rec[i].fSC == sc && rec[i].fDC == dc) {
+ if (mode) {
+ *mode = SkPorterDuff::Mode(i);
+ }
+ return true;
+ }
+ }
+ }
+
+ // no coefficients, or not found in our table
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_DEBUG
+static void unit_test() {
+ for (unsigned a = 0; a <= 255; a++) {
+ for (unsigned c = 0; c <= a; c++) {
+ SkPMColor pm = SkPackARGB32(a, c, c, c);
+ for (unsigned aa = 0; aa <= 255; aa++) {
+ for (unsigned cc = 0; cc <= aa; cc++) {
+ SkPMColor pm2 = SkPackARGB32(aa, cc, cc, cc);
+
+ const size_t N = SK_ARRAY_COUNT(gProcCoeffs);
+ for (size_t i = 0; i < N; i++) {
+ gProcCoeffs[i].fProc(pm, pm2);
+ }
+ }
+ }
+ }
+ }
+}
+#endif
+
+SkXfermodeProc SkPorterDuff::GetXfermodeProc(Mode mode) {
+#ifdef SK_DEBUGx
+ static bool gUnitTest;
+ if (!gUnitTest) {
+ gUnitTest = true;
+ unit_test();
+ }
+#endif
+
+ SkXfermodeProc proc = NULL;
+
+ if ((unsigned)mode < SkPorterDuff::kModeCount) {
+ proc = gProcCoeffs[mode].fProc;
+ }
+ return proc;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//////////// 16bit xfermode procs
+
+#ifdef SK_DEBUG
+static bool require_255(SkPMColor src) { return SkGetPackedA32(src) == 0xFF; }
+static bool require_0(SkPMColor src) { return SkGetPackedA32(src) == 0; }
+#endif
+
+static uint16_t src_modeproc16_255(SkPMColor src, uint16_t dst) {
+ SkASSERT(require_255(src));
+ return SkPixel32ToPixel16(src);
+}
+
+static uint16_t dst_modeproc16(SkPMColor src, uint16_t dst) {
+ return dst;
+}
+
+static uint16_t srcover_modeproc16_0(SkPMColor src, uint16_t dst) {
+ SkASSERT(require_0(src));
+ return dst;
+}
+
+static uint16_t srcover_modeproc16_255(SkPMColor src, uint16_t dst) {
+ SkASSERT(require_255(src));
+ return SkPixel32ToPixel16(src);
+}
+
+static uint16_t dstover_modeproc16_0(SkPMColor src, uint16_t dst) {
+ SkASSERT(require_0(src));
+ return dst;
+}
+
+static uint16_t dstover_modeproc16_255(SkPMColor src, uint16_t dst) {
+ SkASSERT(require_255(src));
+ return dst;
+}
+
+static uint16_t srcin_modeproc16_255(SkPMColor src, uint16_t dst) {
+ SkASSERT(require_255(src));
+ return SkPixel32ToPixel16(src);
+}
+
+static uint16_t dstin_modeproc16_255(SkPMColor src, uint16_t dst) {
+ SkASSERT(require_255(src));
+ return dst;
+}
+
+static uint16_t dstout_modeproc16_0(SkPMColor src, uint16_t dst) {
+ SkASSERT(require_0(src));
+ return dst;
+}
+
+static uint16_t srcatop_modeproc16(SkPMColor src, uint16_t dst) {
+ unsigned isa = 255 - SkGetPackedA32(src);
+
+ return SkPackRGB16(
+ SkPacked32ToR16(src) + SkAlphaMulAlpha(SkGetPackedR16(dst), isa),
+ SkPacked32ToG16(src) + SkAlphaMulAlpha(SkGetPackedG16(dst), isa),
+ SkPacked32ToB16(src) + SkAlphaMulAlpha(SkGetPackedB16(dst), isa));
+}
+
+static uint16_t srcatop_modeproc16_0(SkPMColor src, uint16_t dst) {
+ SkASSERT(require_0(src));
+ return dst;
+}
+
+static uint16_t srcatop_modeproc16_255(SkPMColor src, uint16_t dst) {
+ SkASSERT(require_255(src));
+ return SkPixel32ToPixel16(src);
+}
+
+static uint16_t dstatop_modeproc16_255(SkPMColor src, uint16_t dst) {
+ SkASSERT(require_255(src));
+ return dst;
+}
+
+/*********
+ darken and lighten boil down to this.
+
+ darken = (1 - Sa) * Dc + min(Sc, Dc)
+ lighten = (1 - Sa) * Dc + max(Sc, Dc)
+
+ if (Sa == 0) these become
+ darken = Dc + min(0, Dc) = 0
+ lighten = Dc + max(0, Dc) = Dc
+
+ if (Sa == 1) these become
+ darken = min(Sc, Dc)
+ lighten = max(Sc, Dc)
+*/
+
+static uint16_t darken_modeproc16_0(SkPMColor src, uint16_t dst) {
+ SkASSERT(require_0(src));
+ return 0;
+}
+
+static uint16_t darken_modeproc16_255(SkPMColor src, uint16_t dst) {
+ SkASSERT(require_255(src));
+ unsigned r = SkFastMin32(SkPacked32ToR16(src), SkGetPackedR16(dst));
+ unsigned g = SkFastMin32(SkPacked32ToG16(src), SkGetPackedG16(dst));
+ unsigned b = SkFastMin32(SkPacked32ToB16(src), SkGetPackedB16(dst));
+ return SkPackRGB16(r, g, b);
+}
+
+static uint16_t lighten_modeproc16_0(SkPMColor src, uint16_t dst) {
+ SkASSERT(require_0(src));
+ return dst;
+}
+
+static uint16_t lighten_modeproc16_255(SkPMColor src, uint16_t dst) {
+ SkASSERT(require_255(src));
+ unsigned r = SkMax32(SkPacked32ToR16(src), SkGetPackedR16(dst));
+ unsigned g = SkMax32(SkPacked32ToG16(src), SkGetPackedG16(dst));
+ unsigned b = SkMax32(SkPacked32ToB16(src), SkGetPackedB16(dst));
+ return SkPackRGB16(r, g, b);
+}
+
+struct Proc16Rec {
+ SkXfermodeProc16 fProc16_0;
+ SkXfermodeProc16 fProc16_255;
+ SkXfermodeProc16 fProc16_General;
+};
+
+static const Proc16Rec gPorterDuffModeProcs16[] = {
+ { NULL, NULL, NULL }, // CLEAR
+ { NULL, src_modeproc16_255, NULL },
+ { dst_modeproc16, dst_modeproc16, dst_modeproc16 },
+ { srcover_modeproc16_0, srcover_modeproc16_255, NULL },
+ { dstover_modeproc16_0, dstover_modeproc16_255, NULL },
+ { NULL, srcin_modeproc16_255, NULL },
+ { NULL, dstin_modeproc16_255, NULL },
+ { NULL, NULL, NULL },// SRC_OUT
+ { dstout_modeproc16_0, NULL, NULL },
+ { srcatop_modeproc16_0, srcatop_modeproc16_255, srcatop_modeproc16 },
+ { NULL, dstatop_modeproc16_255, NULL },
+ { NULL, NULL, NULL }, // XOR
+ { darken_modeproc16_0, darken_modeproc16_255, NULL },
+ { lighten_modeproc16_0, lighten_modeproc16_255, NULL },
+ { NULL, NULL, NULL },//multiply
+ { NULL, NULL, NULL }// screen
+};
+
+SkXfermodeProc16 SkPorterDuff::GetXfermodeProc16(Mode mode, SkColor srcColor) {
+ SkXfermodeProc16 proc16 = NULL;
+
+ if ((unsigned)mode < SkPorterDuff::kModeCount) {
+ const Proc16Rec& rec = gPorterDuffModeProcs16[mode];
+
+ unsigned a = SkColorGetA(srcColor);
+
+ if (0 == a) {
+ proc16 = rec.fProc16_0;
+ } else if (255 == a) {
+ proc16 = rec.fProc16_255;
+ } else {
+ proc16 = rec.fProc16_General;
+ }
+ }
+ return proc16;
+}
+