aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar vandebo@chromium.org <vandebo@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-02-08 19:28:07 +0000
committerGravatar vandebo@chromium.org <vandebo@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-02-08 19:28:07 +0000
commit48543277728fdf66b993f17421f65fba532a23a2 (patch)
tree0b102b16486415cfb43f79aeb02054213ea1f26f
parent79ac4fd6eb52512094ab762d2ec785390000cdd2 (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.h8
-rw-r--r--src/core/SkXfermode.cpp652
-rw-r--r--src/pdf/SkPDFDevice.cpp10
-rw-r--r--src/pdf/SkPDFFormXObject.cpp8
-rw-r--r--src/pdf/SkPDFGraphicState.cpp81
-rw-r--r--tests/XfermodeTest.cpp30
-rw-r--r--tests/tests_files.mk3
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