/* * 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; }