diff options
Diffstat (limited to 'skia/sgl/SkXfermode.cpp')
-rw-r--r-- | skia/sgl/SkXfermode.cpp | 965 |
1 files changed, 965 insertions, 0 deletions
diff --git a/skia/sgl/SkXfermode.cpp b/skia/sgl/SkXfermode.cpp new file mode 100644 index 0000000..6225e6e --- /dev/null +++ b/skia/sgl/SkXfermode.cpp @@ -0,0 +1,965 @@ +/* + * Copyright (C) 2006 Google Inc. + * + * 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); +} + +/////////////////////////////////////////////////////////////////////////////// + +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; +} + |