diff options
author | vandebo@chromium.org <vandebo@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2011-02-08 19:28:07 +0000 |
---|---|---|
committer | vandebo@chromium.org <vandebo@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2011-02-08 19:28:07 +0000 |
commit | 48543277728fdf66b993f17421f65fba532a23a2 (patch) | |
tree | 0b102b16486415cfb43f79aeb02054213ea1f26f | |
parent | 79ac4fd6eb52512094ab762d2ec785390000cdd2 (diff) |
[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
-rw-r--r-- | include/core/SkXfermode.h | 8 | ||||
-rw-r--r-- | src/core/SkXfermode.cpp | 652 | ||||
-rw-r--r-- | src/pdf/SkPDFDevice.cpp | 10 | ||||
-rw-r--r-- | src/pdf/SkPDFFormXObject.cpp | 8 | ||||
-rw-r--r-- | src/pdf/SkPDFGraphicState.cpp | 81 | ||||
-rw-r--r-- | tests/XfermodeTest.cpp | 30 | ||||
-rw-r--r-- | tests/tests_files.mk | 3 |
7 files changed, 463 insertions, 329 deletions
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,288 +83,6 @@ static inline int clamp_max(int value, int max) { /////////////////////////////////////////////////////////////////////////////// -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; @@ -708,6 +426,340 @@ static SkPMColor exclusion_modeproc(SkPMColor src, SkPMColor dst) { 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); + } + } + } + } +} + +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); +} + +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<Mode>(i); + } + return true; + } + } + return false; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +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; +}; + /////////////////////////////////////////////////////////////////////////////// class SkClearXfermode : public SkProcCoeffXfermode { @@ -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<SkPDFDevice*>(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<SkPDFDict> 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 |