[PDF] Add support for xfermodes / blend modes.
authorvandebo@chromium.org <vandebo@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 8 Feb 2011 19:28:07 +0000 (19:28 +0000)
committervandebo@chromium.org <vandebo@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 8 Feb 2011 19:28:07 +0000 (19:28 +0000)
- 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
src/core/SkXfermode.cpp
src/pdf/SkPDFDevice.cpp
src/pdf/SkPDFFormXObject.cpp
src/pdf/SkPDFGraphicState.cpp
tests/XfermodeTest.cpp [new file with mode: 0644]
tests/tests_files.mk

index 7a064673eb5e2f498f79797137182d056a972f30..948d1dde1d038a60749a482e175a827842c7f9e2 100644 (file)
@@ -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&);
index 8d1531a0a01d5cb489d613debce7929f29ebc22a..71482c1ddbe3b6dcc5456c03ffa3166e43876198 100644 (file)
@@ -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<Mode>(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);
index 9ebc0ca6d736a64621fef63e03a03259bea281dd..8a74556c703c1d4c98edf1608a59ab1b5496db0e 100644 (file)
@@ -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");
index 346bce6e853328cad18167de26aaa80c21e7867d..ef839a3b4ea3bbd51fd781247d3f54b6f819561c 100644 (file)
@@ -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() {
index ff55941d750f0ac60a8cb87c5177dd80869e9554..44419ece4305c53b7eed59cd56dbb95361d4a575 100644 (file)
 
 #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 (file)
index 0000000..6ab6cd7
--- /dev/null
@@ -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)
index 4aa7cc00a410e2b3f4ef353ffd4216fbfbf173c7..1c6a0efd5a0493ac35c2b784e84d861dc609aa09 100644 (file)
@@ -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