pull from trunk
move (and extended) xfermode enum into SkXfermode.h
fix recursion bug in stroking
minor utility code changes for new unittests
diff --git a/Android.mk b/Android.mk
index ef8547d..b2926be 100644
--- a/Android.mk
+++ b/Android.mk
@@ -72,6 +72,7 @@
 	src/effects/SkLayerRasterizer.cpp \
 	src/effects/SkPaintFlagsDrawFilter.cpp \
 	src/effects/SkPixelXorXfermode.cpp \
+	src/effects/SkPorterDuff.cpp \
 	src/effects/SkTransparentShader.cpp \
 	src/images/bmpdecoderhelper.cpp \
 	src/images/SkFDStream.cpp \
diff --git a/include/core/SkGraphics.h b/include/core/SkGraphics.h
index 1862a2b..dd5808a 100644
--- a/include/core/SkGraphics.h
+++ b/include/core/SkGraphics.h
@@ -42,5 +42,15 @@
     static void InstallNewHandler();
 };
 
+class SkAutoGraphics {
+public:
+    SkAutoGraphics() {
+        SkGraphics::Init();
+    }
+    ~SkAutoGraphics() {
+        SkGraphics::Term();
+    }
+};
+
 #endif
 
diff --git a/include/core/SkMath.h b/include/core/SkMath.h
index 0c89065..9198412 100644
--- a/include/core/SkMath.h
+++ b/include/core/SkMath.h
@@ -217,5 +217,12 @@
     return (prod + (prod >> shift)) >> shift;
 }
 
+/** Just the rounding step in SkDiv255Round: round(value / 255)
+ */
+static inline unsigned SkDiv255Round(unsigned prod) {
+    prod += 128;
+    return (prod + (prod >> 8)) >> 8;
+}
+
 #endif
 
diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h
index dd3aa13..5865fe8 100644
--- a/include/core/SkPaint.h
+++ b/include/core/SkPaint.h
@@ -19,6 +19,9 @@
 
 #include "SkColor.h"
 #include "SkMath.h"
+#include "SkXfermode.h"
+
+// DEPRECATED - remove
 #include "SkPorterDuff.h"
 
 class SkAutoGlyphCache;
@@ -37,7 +40,6 @@
 class SkShader;
 class SkDrawLooper;
 class SkTypeface;
-class SkXfermode;
 
 typedef const SkGlyph& (*SkDrawCacheProc)(SkGlyphCache*, const char**,
                                            SkFixed x, SkFixed y);
@@ -456,8 +458,15 @@
         @return         xfermode
     */
     SkXfermode* setXfermode(SkXfermode* xfermode);
-    
-    /** Helper for setXfermode, passing the corresponding xfermode object
+
+    /** Create an xfermode based on the specified Mode, and assign it into the
+        paint, returning the mode that was set. If the Mode is SrcOver, then
+        the paint's xfermode is set to null.
+     */
+    SkXfermode* setXfermode(SkXfermode::Mode);
+
+    /** DEPRECATED
+        Helper for setXfermode, passing the corresponding xfermode object
         returned from the PorterDuff factory.
         @param mode The porter-duff mode used to create an xfermode for the
                     paint.
diff --git a/include/core/SkPath.h b/include/core/SkPath.h
index fc323d3..6d4d670 100644
--- a/include/core/SkPath.h
+++ b/include/core/SkPath.h
@@ -85,7 +85,7 @@
     /** Returns true if the path is flagged as being convex. This is not a
         confirmed by any analysis, it is just the value set earlier.
      */
-    bool isConvex() const { return fIsConvex; }
+    bool isConvex() const { return fIsConvex != 0; }
 
     /** Set the isConvex flag to true or false. Convex paths may draw faster if
         this flag is set, though setting this to true on a path that is in fact
diff --git a/include/core/SkPorterDuff.h b/include/core/SkPorterDuff.h
index 44c5477..52021b1 100644
--- a/include/core/SkPorterDuff.h
+++ b/include/core/SkPorterDuff.h
@@ -21,6 +21,8 @@
 
 class SkXfermode;
 
+/** DEPRECATED - use SkXfermode::Mode instead
+ */
 class SkPorterDuff {
 public:
     /** List of predefined xfermodes. In general, the algebra for the modes
diff --git a/include/core/SkString.h b/include/core/SkString.h
index ae204dc..5ecfb1e 100644
--- a/include/core/SkString.h
+++ b/include/core/SkString.h
@@ -43,12 +43,13 @@
     explicit    SkString(size_t len);
     explicit    SkString(const char text[]);
                 SkString(const char text[], size_t len);
-    explicit    SkString(const SkString&);
+                SkString(const SkString&);
                 ~SkString();
 
     bool        isEmpty() const { return fRec->fLength == 0; }
     size_t      size() const { return (size_t) fRec->fLength; }
     const char* c_str() const { return fRec->data(); }
+    char operator[](size_t n) const { return this->c_str()[n]; }
 
     bool    equals(const SkString&) const;
     bool    equals(const char text[]) const;
@@ -77,6 +78,7 @@
     SkString&   operator=(const SkString&);
 
     char*   writable_str();
+    char& operator[](size_t n) { return this->writable_str()[n]; }
 
     void    reset();
     void    resize(size_t len) { this->set(NULL, len); }
diff --git a/include/core/SkXfermode.h b/include/core/SkXfermode.h
index 6a7edec..7a06467 100644
--- a/include/core/SkXfermode.h
+++ b/include/core/SkXfermode.h
@@ -75,6 +75,69 @@
      */
     virtual bool asCoeff(Coeff* src, Coeff* dst);
 
+    /** List of predefined xfermodes.
+        The algebra for the modes uses the following symbols:
+        Sa, Sc  - source alpha and color
+        Da, Dc - destination alpha and color (before compositing)
+        [a, c] - Resulting (alpha, color) values
+        For these equations, the colors are in premultiplied state.
+        If no xfermode is specified, kSrcOver is assumed.
+     */
+    enum Mode {
+        kClear_Mode,    //!< [0, 0]
+        kSrc_Mode,      //!< [Sa, Sc]
+        kDst_Mode,      //!< [Da, Dc]
+        kSrcOver_Mode,  //!< [Sa + Da - Sa*Da, Rc = Sc + (1 - Sa)*Dc]
+        kDstOver_Mode,  //!< [Sa + Da - Sa*Da, Rc = Dc + (1 - Da)*Sc]
+        kSrcIn_Mode,    //!< [Sa * Da, Sc * Da]
+        kDstIn_Mode,    //!< [Sa * Da, Sa * Dc]
+        kSrcOut_Mode,   //!< [Sa * (1 - Da), Sc * (1 - Da)]
+        kDstOut_Mode,   //!< [Da * (1 - Sa), Dc * (1 - Sa)]
+        kSrcATop_Mode,  //!< [Da, Sc * Da + (1 - Sa) * Dc]
+        kDstATop_Mode,  //!< [Sa, Sa * Dc + Sc * (1 - Da)]
+        kXor_Mode,      //!< [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]
+
+        // these modes are defined in the SVG Compositing standard
+        // http://www.w3.org/TR/2009/WD-SVGCompositing-20090430/
+        kPlus_Mode,
+        kMultiply_Mode,
+        kScreen_Mode,
+        kOverlay_Mode,
+        kDarken_Mode,
+        kLighten_Mode,
+        kColorDodge_Mode,
+        kColorBurn_Mode,
+        kHardLight_Mode,
+        kSoftLight_Mode,
+        kDifference_Mode,
+        kExclusion_Mode,
+
+        kLastMode = kExclusion_Mode
+    };
+
+    /** Return an SkXfermode object for the specified mode.
+     */
+    static SkXfermode* Create(Mode mode);
+
+    /** Return a function pointer to a routine that applies the specified
+        porter-duff transfer mode.
+     */
+    static SkXfermodeProc GetProc(Mode mode);
+
+    /** Return a function pointer to a routine that applies the specified
+        porter-duff transfer mode and srcColor to a 16bit device color. Note,
+        if the mode+srcColor might return a non-opaque color, then there is not
+        16bit proc, and this will return NULL.
+      */
+    static SkXfermodeProc16 GetProc16(Mode mode, SkColor srcColor);
+
+    /** If the specified xfermode advertises itself as one of the porterduff
+        modes (via SkXfermode::Coeff), return true and if not null, set mode
+        to the corresponding porterduff mode. If it is not recognized as a one,
+        return false and ignore the mode parameter.
+     */
+    static bool IsMode(SkXfermode*, Mode* mode);
+
 protected:
     SkXfermode(SkFlattenableReadBuffer& rb) : SkFlattenable(rb) {}
     
@@ -89,6 +152,9 @@
     virtual SkPMColor xferColor(SkPMColor src, SkPMColor dst);
 
 private:
+    enum {
+        kModeCount = kLastMode + 1
+    };
     typedef SkFlattenable INHERITED;
 };
 
diff --git a/src/animator/SkPaintParts.h b/src/animator/SkPaintParts.h
index a8bb8bd..c8c978f 100644
--- a/src/animator/SkPaintParts.h
+++ b/src/animator/SkPaintParts.h
@@ -73,7 +73,7 @@
     virtual void dump(SkAnimateMaker *);
 #endif
     SkTypeface* getTypeface() {
-        return SkTypeface::Create(fontName.c_str(), style); }
+        return SkTypeface::CreateFromName(fontName.c_str(), style); }
 protected:
     virtual bool add();
     SkString fontName;
diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp
index 1441385..2320b1f 100644
--- a/src/core/SkPaint.cpp
+++ b/src/core/SkPaint.cpp
@@ -1437,13 +1437,6 @@
     return mode;
 }
 
-SkXfermode* SkPaint::setPorterDuffXfermode(SkPorterDuff::Mode mode)
-{
-    fXfermode->safeUnref();
-    fXfermode = SkPorterDuff::CreateXfermode(mode);
-    return fXfermode;
-}
-
 SkPathEffect* SkPaint::setPathEffect(SkPathEffect* effect)
 {
     SkRefCnt_SafeAssign(fPathEffect, effect);
@@ -1456,6 +1449,11 @@
     return filter;
 }
 
+// Helpers
+SkXfermode* SkPaint::setXfermode(SkXfermode::Mode mode) {
+    return this->setXfermode(SkXfermode::Create(mode));
+}
+
 ////////////////////////////////////////////////////////////////////////////////////////
 
 bool SkPaint::getFillPath(const SkPath& src, SkPath* dst) const
diff --git a/src/core/SkStroke.cpp b/src/core/SkStroke.cpp
index 30d524e..1fb25a6 100644
--- a/src/core/SkStroke.cpp
+++ b/src/core/SkStroke.cpp
@@ -302,9 +302,12 @@
     bool degenerateBC = !set_normal_unitnormal(pts[1], pts[2], fRadius,
                                                &normalBC, &unitNormalBC);
 
-    if (--subDivide >= 0 &&
-            (degenerateBC || normals_too_curvy(unitNormalAB, unitNormalBC) ||
-             normals_too_curvy(unitNormalBC, *unitNormalCD))) {
+    if (degenerateBC || normals_too_curvy(unitNormalAB, unitNormalBC) ||
+             normals_too_curvy(unitNormalBC, *unitNormalCD)) {
+        // subdivide if we can
+        if (--subDivide < 0) {
+            goto DRAW_LINE;
+        }
         SkPoint     tmp[7];
         SkVector    norm, unit, dummy, unitDummy;
 
diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp
index 9514bfa..ec42e43 100644
--- a/src/core/SkXfermode.cpp
+++ b/src/core/SkXfermode.cpp
@@ -55,6 +55,32 @@
     return sum;
 }
 
+static int clamp_signed_byte(int n) {
+    if (n < 0) {
+        n = 0;
+    } else if (n > 255) {
+        n = 255;
+    }
+    return n;
+}
+
+static int clamp_div255round(int prod) {
+    if (prod <= 0) {
+        return 0;
+    } else if (prod >= 255*255) {
+        return 255;
+    } else {
+        return SkDiv255Round(prod);
+    }
+}
+
+static int clamp_max(int value, int max) {
+    if (value > max) {
+        value = max;
+    }
+    return value;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 bool SkXfermode::asCoeff(Coeff* src, Coeff* dst) {
@@ -440,57 +466,19 @@
                             SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
 }
 
+///////////////////////////////////////////////////////////////////////////////
 
-// kDarken_Mode,   [Sa + Da - Sa·Da, Sc·(1 - Da) + Dc·(1 - Sa) + min(Sc, Dc)]
-
-static inline unsigned darken_p(unsigned src, unsigned dst,
-                                unsigned src_mul, unsigned dst_mul) {
-    return ((dst_mul * src + src_mul * dst) >> 8) + SkMin32(src, dst);
+// kPlus_Mode
+static SkPMColor plus_modeproc(SkPMColor src, SkPMColor dst) {
+    unsigned a = saturated_add(SkGetPackedA32(src), SkGetPackedA32(dst));
+    unsigned r = saturated_add(SkGetPackedR32(src), SkGetPackedR32(dst));
+    unsigned g = saturated_add(SkGetPackedG32(src), SkGetPackedG32(dst));
+    unsigned b = saturated_add(SkGetPackedB32(src), SkGetPackedB32(dst));
+    return SkPackARGB32(a, r, g, b);
 }
 
-static SkPMColor darken_modeproc(SkPMColor src, SkPMColor dst) {
-    unsigned sa = SkGetPackedA32(src);
-    unsigned da = SkGetPackedA32(dst);
-    unsigned src_scale = SkAlpha255To256(255 - sa);
-    unsigned dst_scale = SkAlpha255To256(255 - da);
-
-    unsigned ra = sa + da - SkAlphaMulAlpha(sa, da);
-    unsigned rr = darken_p(SkGetPackedR32(src), SkGetPackedR32(dst),
-                           src_scale, dst_scale);
-    unsigned rg = darken_p(SkGetPackedG32(src), SkGetPackedG32(dst),
-                           src_scale, dst_scale);
-    unsigned rb = darken_p(SkGetPackedB32(src), SkGetPackedB32(dst),
-                           src_scale, dst_scale);
-
-    return SkPackARGB32(ra, SkFastMin32(rr, ra),
-                        SkFastMin32(rg, ra), SkFastMin32(rb, ra));
-}
-
-// kLighten_Mode,  [Sa + Da - Sa·Da, Sc·(1 - Da) + Dc·(1 - Sa) + max(Sc, Dc)]
-static inline unsigned lighten_p(unsigned src, unsigned dst,
-                                 unsigned src_mul, unsigned dst_mul) {
-    return ((dst_mul * src + src_mul * dst) >> 8) + SkMax32(src, dst);
-}
-
-static SkPMColor lighten_modeproc(SkPMColor src, SkPMColor dst) {
-    unsigned sa = SkGetPackedA32(src);
-    unsigned da = SkGetPackedA32(dst);
-    unsigned src_scale = SkAlpha255To256(255 - sa);
-    unsigned dst_scale = SkAlpha255To256(255 - da);
-    
-    unsigned ra = sa + da - SkAlphaMulAlpha(sa, da);
-    unsigned rr = lighten_p(SkGetPackedR32(src), SkGetPackedR32(dst),
-                            src_scale, dst_scale);
-    unsigned rg = lighten_p(SkGetPackedG32(src), SkGetPackedG32(dst),
-                            src_scale, dst_scale);
-    unsigned rb = lighten_p(SkGetPackedB32(src), SkGetPackedB32(dst),
-                            src_scale, dst_scale);
-
-    return SkPackARGB32(ra, SkFastMin32(rr, ra),
-                        SkFastMin32(rg, ra), SkFastMin32(rb, ra));
-}
-    
-static SkPMColor mult_modeproc(SkPMColor src, SkPMColor dst) {
+// 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));
@@ -498,23 +486,225 @@
     return SkPackARGB32(a, r, g, b);
 }
 
-static inline int screen_byte(int a, int b) {
+// kScreen_Mode
+static inline int srcover_byte(int a, int b) {
     return a + b - SkAlphaMulAlpha(a, b);
 }
-
 static SkPMColor screen_modeproc(SkPMColor src, SkPMColor dst) {
-    int a = screen_byte(SkGetPackedA32(src), SkGetPackedA32(dst));
-    int r = screen_byte(SkGetPackedR32(src), SkGetPackedR32(dst));
-    int g = screen_byte(SkGetPackedG32(src), SkGetPackedG32(dst));
-    int b = screen_byte(SkGetPackedB32(src), SkGetPackedB32(dst));
+    int a = srcover_byte(SkGetPackedA32(src), SkGetPackedA32(dst));
+    int r = srcover_byte(SkGetPackedR32(src), SkGetPackedR32(dst));
+    int g = srcover_byte(SkGetPackedG32(src), SkGetPackedG32(dst));
+    int b = srcover_byte(SkGetPackedB32(src), SkGetPackedB32(dst));
     return SkPackARGB32(a, r, g, b);
 }
 
-static SkPMColor add_modeproc(SkPMColor src, SkPMColor dst) {
-    unsigned a = saturated_add(SkGetPackedA32(src), SkGetPackedA32(dst));
-    unsigned r = saturated_add(SkGetPackedR32(src), SkGetPackedR32(dst));
-    unsigned g = saturated_add(SkGetPackedG32(src), SkGetPackedG32(dst));
-    unsigned b = saturated_add(SkGetPackedB32(src), SkGetPackedB32(dst));
+// kOverlay_Mode
+static inline int overlay_byte(int sc, int dc, int sa, int da) {
+    int tmp = sc * (255 - da) + dc * (255 - sa);
+    int rc;
+    if (2 * dc <= da) {
+        rc = 2 * sc * dc;
+    } else {
+        rc = sa * da - 2 * (da - dc) * (sa - sc);
+    }
+    return clamp_div255round(rc + tmp);
+}
+static SkPMColor overlay_modeproc(SkPMColor src, SkPMColor dst) {
+    int sa = SkGetPackedA32(src);
+    int da = SkGetPackedA32(dst);
+    int a = srcover_byte(sa, da);
+    int r = overlay_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
+    int g = overlay_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
+    int b = overlay_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
+    return SkPackARGB32(a, r, g, b);
+}
+
+// kDarken_Mode
+static inline int darken_byte(int sc, int dc, int sa, int da) {
+    int sd = sc * da;
+    int ds = dc * sa;
+    if (sd < ds) {
+        // srcover
+        return sc + dc - SkDiv255Round(ds);
+    } else {
+        // dstover
+        return dc + sc - SkDiv255Round(sd);
+    }
+}
+static SkPMColor darken_modeproc(SkPMColor src, SkPMColor dst) {
+    int sa = SkGetPackedA32(src);
+    int da = SkGetPackedA32(dst);
+    int a = srcover_byte(sa, da);
+    int r = darken_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
+    int g = darken_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
+    int b = darken_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
+    return SkPackARGB32(a, r, g, b);
+}
+
+// kLighten_Mode
+static inline int lighten_byte(int sc, int dc, int sa, int da) {
+    int sd = sc * da;
+    int ds = dc * sa;
+    if (sd > ds) {
+        // srcover
+        return sc + dc - SkDiv255Round(ds);
+    } else {
+        // dstover
+        return dc + sc - SkDiv255Round(sd);
+    }
+}
+static SkPMColor lighten_modeproc(SkPMColor src, SkPMColor dst) {
+    int sa = SkGetPackedA32(src);
+    int da = SkGetPackedA32(dst);
+    int a = srcover_byte(sa, da);
+    int r = lighten_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
+    int g = lighten_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
+    int b = lighten_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
+    return SkPackARGB32(a, r, g, b);
+}
+
+// kColorDodge_Mode
+static inline int colordodge_byte(int sc, int dc, int sa, int da) {
+    int diff = sa - sc;
+    int rc;
+    if (0 == diff) {
+        rc = sa * da + sc * (255 - da) + dc * (255 - sa);
+        rc = SkDiv255Round(rc);
+    } else {
+        int tmp = (dc * sa << 15) / (da * diff);
+        rc = SkDiv255Round(sa * da) * tmp >> 15;
+        // don't clamp here, since we'll do it in our modeproc
+    }
+    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);
 }
 
@@ -711,8 +901,6 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-#include "SkPorterDuff.h"
-
 struct ProcCoeff {
     SkXfermodeProc      fProc;
     SkXfermode::Coeff   fSC;
@@ -734,16 +922,24 @@
     { srcatop_modeproc, SkXfermode::kDA_Coeff,      SkXfermode::kISA_Coeff },
     { dstatop_modeproc, SkXfermode::kIDA_Coeff,     SkXfermode::kSA_Coeff },
     { xor_modeproc,     SkXfermode::kIDA_Coeff,     SkXfermode::kISA_Coeff },
-    { darken_modeproc,  CANNOT_USE_COEFF,           CANNOT_USE_COEFF },
-    { lighten_modeproc, CANNOT_USE_COEFF,           CANNOT_USE_COEFF },
-    { mult_modeproc,    SkXfermode::kZero_Coeff,    SkXfermode::kSC_Coeff },
-    { screen_modeproc,  SkXfermode::kOne_Coeff,     SkXfermode::kISC_Coeff },
-    { add_modeproc,     CANNOT_USE_COEFF,           CANNOT_USE_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* SkPorterDuff::CreateXfermode(SkPorterDuff::Mode mode) {
-    SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == SkPorterDuff::kModeCount);
-    SkASSERT((unsigned)mode < SkPorterDuff::kModeCount);
+SkXfermode* SkXfermode::Create(Mode mode) {
+    SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
+    SkASSERT((unsigned)mode < kModeCount);
 
     switch (mode) {
         case kClear_Mode:
@@ -756,23 +952,22 @@
             return SkNEW(SkDstInXfermode);
         case kDstOut_Mode:
             return SkNEW(SkDstOutXfermode);
-        // these two can't be represented with Coeff
-        case kDarken_Mode:
-            return SkNEW_ARGS(SkProcXfermode, (darken_modeproc));
-        case kLighten_Mode:
-            return SkNEW_ARGS(SkProcXfermode, (lighten_modeproc));
         // use the table 
         default: {
             const ProcCoeff& rec = gProcCoeffs[mode];
-            SkASSERT((unsigned)rec.fSC < SkXfermode::kCoeffCount);
-            SkASSERT((unsigned)rec.fDC < SkXfermode::kCoeffCount);
-            return SkNEW_ARGS(SkProcCoeffXfermode, (rec.fProc,
-                                                    rec.fSC, rec.fDC));
+            if ((unsigned)rec.fSC < SkXfermode::kCoeffCount &&
+                    (unsigned)rec.fDC < SkXfermode::kCoeffCount) {
+                return SkNEW_ARGS(SkProcCoeffXfermode, (rec.fProc,
+                                                        rec.fSC,
+                                                        rec.fDC));
+            } else {
+                return SkNEW_ARGS(SkProcXfermode, (rec.fProc));
+            }
         }
     }
 }
 
-bool SkPorterDuff::IsMode(SkXfermode* xfer, Mode* mode) {
+bool SkXfermode::IsMode(SkXfermode* xfer, Mode* mode) {
     if (NULL == xfer) {
         if (mode) {
             *mode = kSrcOver_Mode;
@@ -789,7 +984,7 @@
         for (size_t i = 0; i < SK_ARRAY_COUNT(gProcCoeffs); i++) {
             if (rec[i].fSC == sc && rec[i].fDC == dc) {
                 if (mode) {
-                    *mode = SkPorterDuff::Mode(i);
+                    *mode = static_cast<Mode>(i);
                 }
                 return true;
             }
@@ -800,40 +995,9 @@
     return false;
 }
 
-///////////////////////////////////////////////////////////////////////////////
-
-#ifdef SK_DEBUGx
-static void unit_test() {
-    for (unsigned a = 0; a <= 255; a++) {
-        for (unsigned c = 0; c <= a; c++) {
-            SkPMColor pm = SkPackARGB32(a, c, c, c);
-            for (unsigned aa = 0; aa <= 255; aa++) {
-                for (unsigned cc = 0; cc <= aa; cc++) {
-                    SkPMColor pm2 = SkPackARGB32(aa, cc, cc, cc);
-                    
-                    const size_t N = SK_ARRAY_COUNT(gProcCoeffs);
-                    for (size_t i = 0; i < N; i++) {
-                        gProcCoeffs[i].fProc(pm, pm2);
-                    }
-                }
-            }
-        }
-    }            
-}
-#endif
-
-SkXfermodeProc SkPorterDuff::GetXfermodeProc(Mode mode) {
-#ifdef SK_DEBUGx
-    static bool gUnitTest;
-    if (!gUnitTest) {
-        gUnitTest = true;
-        unit_test();
-    }
-#endif
-
+SkXfermodeProc SkXfermode::GetProc(Mode mode) {
     SkXfermodeProc  proc = NULL;
-
-    if ((unsigned)mode < SkPorterDuff::kModeCount) {
+    if ((unsigned)mode < kModeCount) {
         proc = gProcCoeffs[mode].fProc;
     }
     return proc;
@@ -962,7 +1126,7 @@
     SkXfermodeProc16    fProc16_General;
 };
 
-static const Proc16Rec gPorterDuffModeProcs16[] = {
+static const Proc16Rec gModeProcs16[] = {
     { NULL,                 NULL,                   NULL            }, // CLEAR
     { NULL,                 src_modeproc16_255,     NULL            },
     { dst_modeproc16,       dst_modeproc16,         dst_modeproc16  },
@@ -975,18 +1139,25 @@
     { srcatop_modeproc16_0, srcatop_modeproc16_255, srcatop_modeproc16  },
     { NULL,                 dstatop_modeproc16_255, NULL            },
     { NULL,                 NULL,                   NULL            }, // XOR
-    { darken_modeproc16_0,  darken_modeproc16_255,  NULL            },
-    { lighten_modeproc16_0, lighten_modeproc16_255, NULL            },
-    { NULL,                 NULL,                   NULL            },//multiply
-    { NULL,                 NULL,                   NULL            }// screen
+
+    { NULL,                 NULL,                   NULL            }, // plus
+    { NULL,                 NULL,                   NULL            }, // multiply
+    { NULL,                 NULL,                   NULL            }, // screen
+    { NULL,                 NULL,                   NULL            }, // overlay
+    { darken_modeproc16_0,  darken_modeproc16_255,  NULL            }, // darken
+    { lighten_modeproc16_0, lighten_modeproc16_255, NULL            }, // lighten
+    { NULL,                 NULL,                   NULL            }, // colordodge
+    { NULL,                 NULL,                   NULL            }, // colorburn
+    { NULL,                 NULL,                   NULL            }, // hardlight
+    { NULL,                 NULL,                   NULL            }, // softlight
+    { NULL,                 NULL,                   NULL            }, // difference
+    { NULL,                 NULL,                   NULL            }, // exclusion
 };
 
-SkXfermodeProc16 SkPorterDuff::GetXfermodeProc16(Mode mode, SkColor srcColor) {
+SkXfermodeProc16 SkXfermode::GetProc16(Mode mode, SkColor srcColor) {
     SkXfermodeProc16  proc16 = NULL;
-
-    if ((unsigned)mode < SkPorterDuff::kModeCount) {
-        const Proc16Rec& rec = gPorterDuffModeProcs16[mode];
-        
+    if ((unsigned)mode < kModeCount) {
+        const Proc16Rec& rec = gModeProcs16[mode];
         unsigned a = SkColorGetA(srcColor);
 
         if (0 == a) {
diff --git a/src/effects/SkPorterDuff.cpp b/src/effects/SkPorterDuff.cpp
new file mode 100644
index 0000000..42f93b8
--- /dev/null
+++ b/src/effects/SkPorterDuff.cpp
@@ -0,0 +1,75 @@
+#include "SkPorterDuff.h"
+#include "SkXfermode.h"
+
+/*  This file just exists as a compatibility layer, gluing the PorterDuff API
+    into the (extended) SkXfermode API
+ */
+
+#define MAKE_PAIR(mode) { SkPorterDuff::k##mode##_Mode, SkXfermode::k##mode##_Mode }
+
+// this table must be in SkPorterDuff::Mode order, so it can be indexed directly
+// with a porterduff mode.
+static const struct Pair {
+    SkPorterDuff::Mode  fPD;
+    SkXfermode::Mode    fXF;
+} gPairs[] = {
+    MAKE_PAIR(Clear),
+    MAKE_PAIR(Src),
+    MAKE_PAIR(Dst),
+    MAKE_PAIR(SrcOver),
+    MAKE_PAIR(DstOver),
+    MAKE_PAIR(SrcIn),
+    MAKE_PAIR(DstIn),
+    MAKE_PAIR(SrcOut),
+    MAKE_PAIR(DstOut),
+    MAKE_PAIR(SrcATop),
+    MAKE_PAIR(DstATop),
+    MAKE_PAIR(Xor),
+    MAKE_PAIR(Darken),
+    MAKE_PAIR(Lighten),
+    MAKE_PAIR(Multiply),
+    MAKE_PAIR(Screen),
+    { SkPorterDuff::kAdd_Mode, SkXfermode::kPlus_Mode }
+};
+
+static bool find_pdmode(SkXfermode::Mode src, SkPorterDuff::Mode* dst) {
+    const Pair* pairs = gPairs;
+    for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) {
+        if (pairs[i].fXF == src) {
+            if (dst) {
+                *dst = pairs[i].fPD;
+            }
+            return true;
+        }
+    }
+    return false;
+}
+
+SkXfermode* SkPorterDuff::CreateXfermode(SkPorterDuff::Mode mode) {
+    const Pair& pair = gPairs[mode];
+    SkASSERT(pair.fPD == mode);
+    return SkXfermode::Create(pair.fXF);
+}
+
+bool SkPorterDuff::IsMode(SkXfermode* xfer, Mode* pdmode) {
+    SkXfermode::Mode xfmode;
+    if (!SkXfermode::IsMode(xfer, &xfmode)) {
+        return false;
+    }
+    return find_pdmode(xfmode, pdmode);
+}
+
+SkXfermodeProc SkPorterDuff::GetXfermodeProc(Mode mode) {
+    return SkXfermode::GetProc(gPairs[mode].fXF);
+}
+
+SkXfermodeProc16 SkPorterDuff::GetXfermodeProc16(Mode mode, SkColor srcColor) {
+    return SkXfermode::GetProc16(gPairs[mode].fXF, srcColor);
+}
+
+// DEPRECATED
+#include "SkPaint.h"
+SkXfermode* SkPaint::setPorterDuffXfermode(SkPorterDuff::Mode mode) {
+    return this->setXfermode(SkPorterDuff::CreateXfermode(mode));
+}
+
diff --git a/src/ports/SkFontHost_FreeType.cpp b/src/ports/SkFontHost_FreeType.cpp
index 556b307..7aa14b2 100644
--- a/src/ports/SkFontHost_FreeType.cpp
+++ b/src/ports/SkFontHost_FreeType.cpp
@@ -75,7 +75,9 @@
     virtual ~SkScalerContext_FreeType();
 
     bool success() const {
-        return fFaceRec != NULL && fFTSize != NULL;
+        return fFaceRec != NULL &&
+               fFTSize != NULL &&
+               fFace != NULL;
     }
 
 protected: