From 48543277728fdf66b993f17421f65fba532a23a2 Mon Sep 17 00:00:00 2001 From: "vandebo@chromium.org" Date: Tue, 8 Feb 2011 19:28:07 +0000 Subject: [PDF] Add support for xfermodes / blend modes. - Change SkGraphicState to track and set the blend mode (xfermode) for modes built in to PDF (non porter duff modes + src over). - Add SkXfermode::asMode() to retrieve xfermode as an enum for non porter duff modes. - Move SkXfermode.cpp around a bit to support asMode() -- Generally move utility functions toward the top of the file. - Make SkPDFFormXObject an isolated transparency group, as it used for saveLayer, which draws on transparent, not the device background. - Set the graphic state in drawDevice and drawBitmap in order to get the right xfermode and alpha. Review URL: http://codereview.appspot.com/4131043 git-svn-id: http://skia.googlecode.com/svn/trunk@774 2bbb7eff-a529-9590-31e7-b0007b416f81 --- include/core/SkXfermode.h | 8 + src/core/SkXfermode.cpp | 1074 +++++++++++++++++++++-------------------- src/pdf/SkPDFDevice.cpp | 10 +- src/pdf/SkPDFFormXObject.cpp | 8 + src/pdf/SkPDFGraphicState.cpp | 81 +++- tests/XfermodeTest.cpp | 30 ++ tests/tests_files.mk | 3 +- 7 files changed, 674 insertions(+), 540 deletions(-) create mode 100644 tests/XfermodeTest.cpp diff --git a/include/core/SkXfermode.h b/include/core/SkXfermode.h index 7a064673eb..948d1dde1d 100644 --- a/include/core/SkXfermode.h +++ b/include/core/SkXfermode.h @@ -115,6 +115,13 @@ public: kLastMode = kExclusion_Mode }; + /** If the xfermode is one of the modes in the Mode enum, then asMode() + returns true and sets (if not null) mode accordingly. + This is a better version of IsMode(), which is only able to report + about modes that are expressible as coefficients. + */ + virtual bool asMode(Mode* mode); + /** Return an SkXfermode object for the specified mode. */ static SkXfermode* Create(Mode mode); @@ -182,6 +189,7 @@ public: // overrides from SkFlattenable virtual Factory getFactory() { return CreateProc; } virtual void flatten(SkFlattenableWriteBuffer&); + virtual bool asMode(SkXfermode::Mode* mode); protected: SkProcXfermode(SkFlattenableReadBuffer&); diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp index 8d1531a0a0..71482c1ddb 100644 --- a/src/core/SkXfermode.cpp +++ b/src/core/SkXfermode.cpp @@ -83,408 +83,126 @@ static inline int clamp_max(int value, int max) { /////////////////////////////////////////////////////////////////////////////// -bool SkXfermode::asCoeff(Coeff* src, Coeff* dst) { - return false; +// kClear_Mode, //!< [0, 0] +static SkPMColor clear_modeproc(SkPMColor src, SkPMColor dst) { + return 0; } -SkPMColor SkXfermode::xferColor(SkPMColor src, SkPMColor dst) { - // no-op. subclasses should override this - return dst; +// kSrc_Mode, //!< [Sa, Sc] +static SkPMColor src_modeproc(SkPMColor src, SkPMColor dst) { + return src; } -void SkXfermode::xfer32(SK_RESTRICT SkPMColor dst[], - const SK_RESTRICT SkPMColor src[], int count, - const SK_RESTRICT SkAlpha aa[]) { - SkASSERT(dst && src && count >= 0); +// kDst_Mode, //!< [Da, Dc] +static SkPMColor dst_modeproc(SkPMColor src, SkPMColor dst) { + return dst; +} - 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; - } - } - } +// kSrcOver_Mode, //!< [Sa + Da - Sa*Da, Sc + (1 - Sa)*Dc] +static SkPMColor srcover_modeproc(SkPMColor src, SkPMColor dst) { +#if 0 + // this is the old, more-correct way, but it doesn't guarantee that dst==255 + // will always stay opaque + return src + SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src))); +#else + // this is slightly faster, but more importantly guarantees that dst==255 + // will always stay opaque + return src + SkAlphaMulQ(dst, 256 - SkGetPackedA32(src)); +#endif } -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); +// kDstOver_Mode, //!< [Sa + Da - Sa*Da, Dc + (1 - Da)*Sc] +static SkPMColor dstover_modeproc(SkPMColor src, SkPMColor dst) { + // this is the reverse of srcover, just flipping src and dst + // see srcover's comment about the 256 for opaqueness guarantees + return dst + SkAlphaMulQ(src, 256 - SkGetPackedA32(dst)); +} - 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); - } - } - } +// kSrcIn_Mode, //!< [Sa * Da, Sc * Da] +static SkPMColor srcin_modeproc(SkPMColor src, SkPMColor dst) { + return SkAlphaMulQ(src, SkAlpha255To256(SkGetPackedA32(dst))); } -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); - } - } - } +// kDstIn_Mode, //!< [Sa * Da, Sa * Dc] +static SkPMColor dstin_modeproc(SkPMColor src, SkPMColor dst) { + return SkAlphaMulQ(dst, SkAlpha255To256(SkGetPackedA32(src))); } -void SkXfermode::xferA8(SK_RESTRICT SkAlpha dst[], - const SkPMColor src[], int count, - const SK_RESTRICT SkAlpha aa[]) -{ - SkASSERT(dst && src && count >= 0); +// kSrcOut_Mode, //!< [Sa * (1 - Da), Sc * (1 - Da)] +static SkPMColor srcout_modeproc(SkPMColor src, SkPMColor dst) { + return SkAlphaMulQ(src, SkAlpha255To256(255 - SkGetPackedA32(dst))); +} - 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); - } - } - } +// 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; -void SkProcXfermode::xfer32(SK_RESTRICT SkPMColor dst[], - const SK_RESTRICT SkPMColor src[], int count, - const SK_RESTRICT SkAlpha aa[]) { - SkASSERT(dst && src && count >= 0); + 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))); +} - SkXfermodeProc proc = fProc; +// 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; - 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; - } - } - } - } + 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))); } -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); +// 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; - SkXfermodeProc proc = fProc; + 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))); +} - 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); - } - } - } - } +/////////////////////////////////////////////////////////////////////////////// + +// kPlus_Mode +static SkPMColor plus_modeproc(SkPMColor src, SkPMColor dst) { + unsigned b = saturated_add(SkGetPackedB32(src), SkGetPackedB32(dst)); + unsigned g = saturated_add(SkGetPackedG32(src), SkGetPackedG32(dst)); + unsigned r = saturated_add(SkGetPackedR32(src), SkGetPackedR32(dst)); + unsigned a = saturated_add(SkGetPackedA32(src), SkGetPackedA32(dst)); + return SkPackARGB32(a, r, g, b); } -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 + Da - Sa*Da, Sc + (1 - Sa)*Dc] -static SkPMColor srcover_modeproc(SkPMColor src, SkPMColor dst) { -#if 0 - // this is the old, more-correct way, but it doesn't guarantee that dst==255 - // will always stay opaque - return src + SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src))); -#else - // this is slightly faster, but more importantly guarantees that dst==255 - // will always stay opaque - return src + SkAlphaMulQ(dst, 256 - SkGetPackedA32(src)); -#endif -} - -// kDstOver_Mode, //!< [Sa + Da - Sa*Da, Dc + (1 - Da)*Sc] -static SkPMColor dstover_modeproc(SkPMColor src, SkPMColor dst) { - // this is the reverse of srcover, just flipping src and dst - // see srcover's comment about the 256 for opaqueness guarantees - return dst + SkAlphaMulQ(src, 256 - SkGetPackedA32(dst)); -} - -// 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))); -} - -/////////////////////////////////////////////////////////////////////////////// - -// kPlus_Mode -static SkPMColor plus_modeproc(SkPMColor src, SkPMColor dst) { - unsigned b = saturated_add(SkGetPackedB32(src), SkGetPackedB32(dst)); - unsigned g = saturated_add(SkGetPackedG32(src), SkGetPackedG32(dst)); - unsigned r = saturated_add(SkGetPackedR32(src), SkGetPackedR32(dst)); - unsigned a = saturated_add(SkGetPackedA32(src), SkGetPackedA32(dst)); - return SkPackARGB32(a, r, g, b); -} - -// kMultiply_Mode -static SkPMColor multiply_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); -} +// kMultiply_Mode +static SkPMColor multiply_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); +} // kScreen_Mode static inline int srcover_byte(int a, int b) { @@ -575,138 +293,472 @@ static inline int colordodge_byte(int sc, int dc, int sa, int da) { rc = SkDiv255Round(sa * da) * tmp >> 15; // don't clamp here, since we'll do it in our modeproc } - return rc; + return rc; +} +static SkPMColor colordodge_modeproc(SkPMColor src, SkPMColor dst) { + // added to avoid div-by-zero in colordodge_byte + if (0 == dst) { + return src; + } + + int sa = SkGetPackedA32(src); + int da = SkGetPackedA32(dst); + int a = srcover_byte(sa, da); + int r = colordodge_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); + int g = colordodge_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); + int b = colordodge_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); + r = clamp_max(r, a); + g = clamp_max(g, a); + b = clamp_max(b, a); + return SkPackARGB32(a, r, g, b); +} + +// kColorBurn_Mode +static inline int colorburn_byte(int sc, int dc, int sa, int da) { + int rc; + if (dc == da && 0 == sc) { + rc = sa * da + dc * (255 - sa); + } else if (0 == sc) { + return SkAlphaMulAlpha(dc, 255 - sa); + } else { + int tmp = (sa * (da - dc) * 256) / (sc * da); + if (tmp > 256) { + tmp = 256; + } + int tmp2 = sa * da; + rc = tmp2 - (tmp2 * tmp >> 8) + sc * (255 - da) + dc * (255 - sa); + } + return SkDiv255Round(rc); +} +static SkPMColor colorburn_modeproc(SkPMColor src, SkPMColor dst) { + // added to avoid div-by-zero in colorburn_byte + if (0 == dst) { + return src; + } + + int sa = SkGetPackedA32(src); + int da = SkGetPackedA32(dst); + int a = srcover_byte(sa, da); + int r = colorburn_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); + int g = colorburn_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); + int b = colorburn_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); + return SkPackARGB32(a, r, g, b); +} + +// kHardLight_Mode +static inline int hardlight_byte(int sc, int dc, int sa, int da) { + int rc; + if (2 * sc <= sa) { + rc = 2 * sc * dc; + } else { + rc = sa * da - 2 * (da - dc) * (sa - sc); + } + return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa)); +} +static SkPMColor hardlight_modeproc(SkPMColor src, SkPMColor dst) { + int sa = SkGetPackedA32(src); + int da = SkGetPackedA32(dst); + int a = srcover_byte(sa, da); + int r = hardlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); + int g = hardlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); + int b = hardlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); + return SkPackARGB32(a, r, g, b); +} + +// returns 255 * sqrt(n/255) +static U8CPU sqrt_unit_byte(U8CPU n) { + return SkSqrtBits(n, 15+4); +} + +// kSoftLight_Mode +static inline int softlight_byte(int sc, int dc, int sa, int da) { + int m = da ? dc * 256 / da : 0; + int rc; + if (2 * sc <= sa) { + rc = dc * (sa + ((2 * sc - sa) * (256 - m) >> 8)); + } else if (4 * dc <= da) { + int tmp = (4 * m * (4 * m + 256) * (m - 256) >> 16) + 7 * m; + rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8); + } else { + int tmp = sqrt_unit_byte(m) - m; + rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8); + } + return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa)); +} +static SkPMColor softlight_modeproc(SkPMColor src, SkPMColor dst) { + int sa = SkGetPackedA32(src); + int da = SkGetPackedA32(dst); + int a = srcover_byte(sa, da); + int r = softlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); + int g = softlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); + int b = softlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); + return SkPackARGB32(a, r, g, b); +} + +// kDifference_Mode +static inline int difference_byte(int sc, int dc, int sa, int da) { + int tmp = SkMin32(sc * da, dc * sa); + return clamp_signed_byte(sc + dc - 2 * SkDiv255Round(tmp)); +} +static SkPMColor difference_modeproc(SkPMColor src, SkPMColor dst) { + int sa = SkGetPackedA32(src); + int da = SkGetPackedA32(dst); + int a = srcover_byte(sa, da); + int r = difference_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); + int g = difference_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); + int b = difference_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); + return SkPackARGB32(a, r, g, b); +} + +// kExclusion_Mode +static inline int exclusion_byte(int sc, int dc, int sa, int da) { + // this equations is wacky, wait for SVG to confirm it + int r = sc * da + dc * sa - 2 * sc * dc + sc * (255 - da) + dc * (255 - sa); + return clamp_div255round(r); +} +static SkPMColor exclusion_modeproc(SkPMColor src, SkPMColor dst) { + int sa = SkGetPackedA32(src); + int da = SkGetPackedA32(dst); + int a = srcover_byte(sa, da); + int r = exclusion_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); + int g = exclusion_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); + int b = exclusion_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); + return SkPackARGB32(a, r, g, b); +} + +struct ProcCoeff { + SkXfermodeProc fProc; + SkXfermode::Coeff fSC; + SkXfermode::Coeff fDC; +}; + +#define CANNOT_USE_COEFF SkXfermode::Coeff(-1) + +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 }, + + { plus_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { multiply_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { screen_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { overlay_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { darken_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { lighten_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { colordodge_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { colorburn_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { hardlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { softlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { difference_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { exclusion_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, +}; + +/////////////////////////////////////////////////////////////////////////////// + +bool SkXfermode::asCoeff(Coeff* src, Coeff* dst) { + return false; +} + +bool SkXfermode::asMode(Mode* mode) { + return IsMode(this, mode); +} + +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); + } + } + } + } } -static SkPMColor colordodge_modeproc(SkPMColor src, SkPMColor dst) { - // added to avoid div-by-zero in colordodge_byte - if (0 == dst) { - return src; - } - int sa = SkGetPackedA32(src); - int da = SkGetPackedA32(dst); - int a = srcover_byte(sa, da); - int r = colordodge_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); - int g = colordodge_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); - int b = colordodge_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); - r = clamp_max(r, a); - g = clamp_max(g, a); - b = clamp_max(b, a); - return SkPackARGB32(a, r, g, b); -} +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; -// kColorBurn_Mode -static inline int colorburn_byte(int sc, int dc, int sa, int da) { - int rc; - if (dc == da && 0 == sc) { - rc = sa * da + dc * (255 - sa); - } else if (0 == sc) { - return SkAlphaMulAlpha(dc, 255 - sa); - } else { - int tmp = (sa * (da - dc) * 256) / (sc * da); - if (tmp > 256) { - tmp = 256; + 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); + } + } } - int tmp2 = sa * da; - rc = tmp2 - (tmp2 * tmp >> 8) + sc * (255 - da) + dc * (255 - sa); - } - return SkDiv255Round(rc); -} -static SkPMColor colorburn_modeproc(SkPMColor src, SkPMColor dst) { - // added to avoid div-by-zero in colorburn_byte - if (0 == dst) { - return src; } - - int sa = SkGetPackedA32(src); - int da = SkGetPackedA32(dst); - int a = srcover_byte(sa, da); - int r = colorburn_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); - int g = colorburn_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); - int b = colorburn_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); - return SkPackARGB32(a, r, g, b); } -// kHardLight_Mode -static inline int hardlight_byte(int sc, int dc, int sa, int da) { - int rc; - if (2 * sc <= sa) { - rc = 2 * sc * dc; - } else { - rc = sa * da - 2 * (da - dc) * (sa - sc); +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); + } + } + } } - return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa)); } -static SkPMColor hardlight_modeproc(SkPMColor src, SkPMColor dst) { - int sa = SkGetPackedA32(src); - int da = SkGetPackedA32(dst); - int a = srcover_byte(sa, da); - int r = hardlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); - int g = hardlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); - int b = hardlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); - return SkPackARGB32(a, r, g, b); + +SkProcXfermode::SkProcXfermode(SkFlattenableReadBuffer& buffer) + : SkXfermode(buffer) { + fProc = (SkXfermodeProc)buffer.readFunctionPtr(); } -// returns 255 * sqrt(n/255) -static U8CPU sqrt_unit_byte(U8CPU n) { - return SkSqrtBits(n, 15+4); +void SkProcXfermode::flatten(SkFlattenableWriteBuffer& buffer) { + buffer.writeFunctionPtr((void*)fProc); } -// kSoftLight_Mode -static inline int softlight_byte(int sc, int dc, int sa, int da) { - int m = da ? dc * 256 / da : 0; - int rc; - if (2 * sc <= sa) { - rc = dc * (sa + ((2 * sc - sa) * (256 - m) >> 8)); - } else if (4 * dc <= da) { - int tmp = (4 * m * (4 * m + 256) * (m - 256) >> 16) + 7 * m; - rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8); - } else { - int tmp = sqrt_unit_byte(m) - m; - rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8); +bool SkProcXfermode::asMode(SkXfermode::Mode* mode) { + for (size_t i = 0; i < SK_ARRAY_COUNT(gProcCoeffs); i++) { + if (gProcCoeffs[i].fProc == fProc) { + if (mode) { + *mode = static_cast(i); + } + return true; + } } - return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa)); -} -static SkPMColor softlight_modeproc(SkPMColor src, SkPMColor dst) { - int sa = SkGetPackedA32(src); - int da = SkGetPackedA32(dst); - int a = srcover_byte(sa, da); - int r = softlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); - int g = softlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); - int b = softlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); - return SkPackARGB32(a, r, g, b); + return false; } -// kDifference_Mode -static inline int difference_byte(int sc, int dc, int sa, int da) { - int tmp = SkMin32(sc * da, dc * sa); - return clamp_signed_byte(sc + dc - 2 * SkDiv255Round(tmp)); -} -static SkPMColor difference_modeproc(SkPMColor src, SkPMColor dst) { - int sa = SkGetPackedA32(src); - int da = SkGetPackedA32(dst); - int a = srcover_byte(sa, da); - int r = difference_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); - int g = difference_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); - int b = difference_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); - return SkPackARGB32(a, r, g, b); -} +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// -// kExclusion_Mode -static inline int exclusion_byte(int sc, int dc, int sa, int da) { - // this equations is wacky, wait for SVG to confirm it - int r = sc * da + dc * sa - 2 * sc * dc + sc * (255 - da) + dc * (255 - sa); - return clamp_div255round(r); -} -static SkPMColor exclusion_modeproc(SkPMColor src, SkPMColor dst) { - int sa = SkGetPackedA32(src); - int da = SkGetPackedA32(dst); - int a = srcover_byte(sa, da); - int r = exclusion_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); - int g = exclusion_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); - int b = exclusion_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); - return SkPackARGB32(a, r, g, b); -} +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; +}; /////////////////////////////////////////////////////////////////////////////// @@ -901,42 +953,6 @@ private: /////////////////////////////////////////////////////////////////////////////// -struct ProcCoeff { - SkXfermodeProc fProc; - SkXfermode::Coeff fSC; - SkXfermode::Coeff fDC; -}; - -#define CANNOT_USE_COEFF SkXfermode::Coeff(-1) - -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 }, - - { plus_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, - { multiply_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, - { screen_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, - { overlay_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, - { darken_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, - { lighten_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, - { colordodge_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, - { colorburn_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, - { hardlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, - { softlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, - { difference_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, - { exclusion_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, -}; - SkXfermode* SkXfermode::Create(Mode mode) { SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount); SkASSERT((unsigned)mode < kModeCount); diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp index 9ebc0ca6d7..8a74556c70 100644 --- a/src/pdf/SkPDFDevice.cpp +++ b/src/pdf/SkPDFDevice.cpp @@ -132,7 +132,7 @@ static inline SkBitmap makeABitmap(int width, int height) { SkPDFDevice::SkPDFDevice(int width, int height) : SkDevice(NULL, makeABitmap(width, height), false), - fWidth(width), + fWidth(width), fHeight(height), fGraphicStackIndex(0) { fGraphicStack[0].fColor = SK_ColorBLACK; @@ -441,19 +441,18 @@ void SkPDFDevice::drawDevice(const SkDraw& d, SkDevice* device, int x, int y, return; } // Assume that a vector capable device means that it's a PDF Device. - // TODO(vandebo) handle the paint (alpha and compositing mode). SkPDFDevice* pdfDevice = static_cast(device); SkMatrix matrix; matrix.setTranslate(x, y); SkMatrix curTransform = setTransform(matrix); + updateGSFromPaint(paint, false); SkPDFFormXObject* xobject = new SkPDFFormXObject(pdfDevice); fXObjectResources.push(xobject); // Transfer reference. fContent.append("/X"); fContent.appendS32(fXObjectResources.count() - 1); fContent.append(" Do\n"); - setTransform(curTransform); } @@ -567,8 +566,8 @@ SkString SkPDFDevice::content(bool flipOrigin) const { #define PAINTCHECK(x,y) NOT_IMPLEMENTED(newPaint.x() y, false) void SkPDFDevice::updateGSFromPaint(const SkPaint& newPaint, bool forText) { - PAINTCHECK(getXfermode, != NULL); - PAINTCHECK(getPathEffect, != NULL); + SkASSERT(newPaint.getPathEffect() == NULL); + PAINTCHECK(getMaskFilter, != NULL); PAINTCHECK(getShader, != NULL); PAINTCHECK(getColorFilter, != NULL); @@ -817,6 +816,7 @@ void SkPDFDevice::internalDrawBitmap(const SkMatrix& matrix, scaled.postScale(subset.width(), subset.height()); scaled.postConcat(matrix); SkMatrix curTransform = setTransform(scaled); + updateGSFromPaint(paint, false); fXObjectResources.push(image); // Transfer reference. fContent.append("/X"); diff --git a/src/pdf/SkPDFFormXObject.cpp b/src/pdf/SkPDFFormXObject.cpp index 346bce6e85..ef839a3b4e 100644 --- a/src/pdf/SkPDFFormXObject.cpp +++ b/src/pdf/SkPDFFormXObject.cpp @@ -39,6 +39,14 @@ SkPDFFormXObject::SkPDFFormXObject(SkPDFDevice* device) { insert("Subtype", new SkPDFName("Form"))->unref(); insert("BBox", device->getMediaBox().get()); insert("Resources", device->getResourceDict().get()); + + // Right now SkPDFFormXObject is only used for saveLayer, which implies + // isolated blending. Do this conditionally if that changes. + SkRefPtr group = new SkPDFDict("Group"); + group->unref(); // SkRefPtr and new both took a reference. + group->insert("S", new SkPDFName("Transparency"))->unref(); + group->insert("I", new SkPDFBool(true))->unref(); // Isolated. + insert("Group", group.get()); } SkPDFFormXObject::~SkPDFFormXObject() { diff --git a/src/pdf/SkPDFGraphicState.cpp b/src/pdf/SkPDFGraphicState.cpp index ff55941d75..44419ece43 100644 --- a/src/pdf/SkPDFGraphicState.cpp +++ b/src/pdf/SkPDFGraphicState.cpp @@ -16,6 +16,44 @@ #include "SkPDFGraphicState.h" #include "SkStream.h" +#include "SkTypes.h" + +namespace { + +const char* blendModeFromXfermode(SkXfermode::Mode mode) { + switch (mode) { + case SkXfermode::kSrcOver_Mode: return "Normal"; + case SkXfermode::kMultiply_Mode: return "Multiply"; + case SkXfermode::kScreen_Mode: return "Screen"; + case SkXfermode::kOverlay_Mode: return "Overlay"; + case SkXfermode::kDarken_Mode: return "Darken"; + case SkXfermode::kLighten_Mode: return "Lighten"; + case SkXfermode::kColorDodge_Mode: return "ColorDodge"; + case SkXfermode::kColorBurn_Mode: return "ColorBurn"; + case SkXfermode::kHardLight_Mode: return "HardLight"; + case SkXfermode::kSoftLight_Mode: return "SoftLight"; + case SkXfermode::kDifference_Mode: return "Difference"; + case SkXfermode::kExclusion_Mode: return "Exclusion"; + + // TODO(vandebo) Figure out if we can support more of these modes. + case SkXfermode::kClear_Mode: + case SkXfermode::kSrc_Mode: + case SkXfermode::kDst_Mode: + case SkXfermode::kDstOver_Mode: + case SkXfermode::kSrcIn_Mode: + case SkXfermode::kDstIn_Mode: + case SkXfermode::kSrcOut_Mode: + case SkXfermode::kDstOut_Mode: + case SkXfermode::kSrcATop_Mode: + case SkXfermode::kDstATop_Mode: + case SkXfermode::kXor_Mode: + case SkXfermode::kPlus_Mode: + return NULL; + } + return NULL; +} + +} SkPDFGraphicState::~SkPDFGraphicState() { SkAutoMutexAcquire lock(canonicalPaintsMutex()); @@ -30,6 +68,7 @@ void SkPDFGraphicState::emitObject(SkWStream* stream, SkPDFCatalog* catalog, SkPDFDict::emitObject(stream, catalog, indirect); } +// static size_t SkPDFGraphicState::getOutputSize(SkPDFCatalog* catalog, bool indirect) { populateDict(); return SkPDFDict::getOutputSize(catalog, indirect); @@ -104,6 +143,18 @@ void SkPDFGraphicState::populateDict() { insert("LW", new SkPDFScalar(fPaint.getStrokeWidth()))->unref(); insert("ML", new SkPDFScalar(fPaint.getStrokeMiter()))->unref(); insert("SA", new SkPDFBool(true))->unref(); // Auto stroke adjustment. + + SkXfermode::Mode xfermode = SkXfermode::kSrcOver_Mode; + // If asMode fails return false, default to kSrcOver_Mode. + if (fPaint.getXfermode()) + fPaint.getXfermode()->asMode(&xfermode); + // If we don't support the mode, just use kSrcOver_Mode. + if (xfermode < 0 || xfermode > SkXfermode::kLastMode || + blendModeFromXfermode(xfermode) == NULL) { + fprintf(stderr, "NOT_IMPLEMENTED: xfermode = %d\n", xfermode); + xfermode = SkXfermode::kSrcOver_Mode; + } + insert("BM", new SkPDFName(blendModeFromXfermode(xfermode)))->unref(); } } @@ -115,9 +166,29 @@ bool SkPDFGraphicState::GSCanonicalEntry::operator==( const SkPaint* b = gs.fPaint; SkASSERT(a != NULL); SkASSERT(b != NULL); - return SkColorGetA(a->getColor()) == SkColorGetA(b->getColor()) && - a->getStrokeCap() == b->getStrokeCap() && - a->getStrokeJoin() == b->getStrokeJoin() && - a->getStrokeWidth() == b->getStrokeWidth() && - a->getStrokeMiter() == b->getStrokeMiter(); + + if (SkColorGetA(a->getColor()) != SkColorGetA(b->getColor()) || + a->getStrokeCap() != b->getStrokeCap() || + a->getStrokeJoin() != b->getStrokeJoin() || + a->getStrokeWidth() != b->getStrokeWidth() || + a->getStrokeMiter() != b->getStrokeMiter()) { + return false; + } + + SkXfermode* aXfermode = a->getXfermode(); + SkXfermode::Mode aXfermodeName = SkXfermode::kSrcOver_Mode; + bool aXfermodeKnown = true; + if (aXfermode) + aXfermodeKnown = aXfermode->asMode(&aXfermodeName); + SkXfermode* bXfermode = b->getXfermode(); + SkXfermode::Mode bXfermodeName = SkXfermode::kSrcOver_Mode; + bool bXfermodeKnown = true; + if (bXfermode) + bXfermodeKnown = bXfermode->asMode(&bXfermodeName); + + if (aXfermodeKnown != bXfermodeKnown) + return false; + if (!aXfermodeKnown) + return aXfermode == bXfermode; + return aXfermodeName == bXfermodeName; } diff --git a/tests/XfermodeTest.cpp b/tests/XfermodeTest.cpp new file mode 100644 index 0000000000..6ab6cd73a8 --- /dev/null +++ b/tests/XfermodeTest.cpp @@ -0,0 +1,30 @@ +#include "Test.h" +#include "SkColor.h" +#include "SkXfermode.h" + +SkPMColor bogusXfermodeProc(SkPMColor src, SkPMColor dst) { + return 42; +} + +static void test_asMode(skiatest::Reporter* reporter) { + for (int mode = 0; mode <= SkXfermode::kLastMode; mode++) { + SkXfermode* xfer = SkXfermode::Create((SkXfermode::Mode) mode); + SkXfermode::Mode reportedMode = (SkXfermode::Mode) -1; + REPORTER_ASSERT(reporter, + xfer != NULL || mode == SkXfermode::kSrcOver_Mode); + if (xfer) { + REPORTER_ASSERT(reporter, xfer->asMode(&reportedMode)); + REPORTER_ASSERT(reporter, reportedMode == mode); + xfer->unref(); + } + } + + SkXfermode* bogusXfer = new SkProcXfermode(bogusXfermodeProc); + SkXfermode::Mode reportedMode = (SkXfermode::Mode) -1; + REPORTER_ASSERT(reporter, !bogusXfer->asMode(&reportedMode)); + REPORTER_ASSERT(reporter, reportedMode == -1); + bogusXfer->unref(); +} + +#include "TestClassDef.h" +DEFINE_TESTCLASS("Xfermode", XfermodeTestClass, test_asMode) diff --git a/tests/tests_files.mk b/tests/tests_files.mk index 4aa7cc00a4..1c6a0efd5a 100644 --- a/tests/tests_files.mk +++ b/tests/tests_files.mk @@ -6,6 +6,7 @@ SOURCE := \ FillPathTest.cpp \ FlateTest.cpp \ GeometryTest.cpp \ + InfRectTest.cpp \ MathTest.cpp \ MatrixTest.cpp \ PackBitsTest.cpp \ @@ -24,4 +25,4 @@ SOURCE := \ Test.cpp \ TestSize.cpp \ UtilsTest.cpp \ - InfRectTest.cpp + XfermodeTest.cpp -- cgit v1.2.3