Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / core / SkXfermode.cpp
index a22035e..0811808 100644 (file)
@@ -8,19 +8,20 @@
 
 
 #include "SkXfermode.h"
+#include "SkXfermode_opts_SSE2.h"
 #include "SkXfermode_proccoeff.h"
 #include "SkColorPriv.h"
-#include "SkFlattenableBuffers.h"
+#include "SkLazyPtr.h"
 #include "SkMathPriv.h"
+#include "SkReadBuffer.h"
 #include "SkString.h"
 #include "SkUtilsArm.h"
+#include "SkWriteBuffer.h"
 
 #if !SK_ARM_NEON_IS_NONE
 #include "SkXfermode_opts_arm_neon.h"
 #endif
 
-SK_DEFINE_INST_COUNT(SkXfermode)
-
 #define SkAlphaMulAlpha(a, b)   SkMulDiv255Round(a, b)
 
 #if 0
@@ -470,16 +471,18 @@ static inline void clipColor(int* r, int* g, int* b, int a) {
     int L = Lum(*r, *g, *b);
     int n = minimum(*r, *g, *b);
     int x = maximum(*r, *g, *b);
-    if(n < 0) {
-       *r = L + SkMulDiv(*r - L, L, L - n);
-       *g = L + SkMulDiv(*g - L, L, L - n);
-       *b = L + SkMulDiv(*b - L, L, L - n);
+    int denom;
+    if ((n < 0) && (denom = L - n)) { // Compute denom and make sure it's non zero
+       *r = L + SkMulDiv(*r - L, L, denom);
+       *g = L + SkMulDiv(*g - L, L, denom);
+       *b = L + SkMulDiv(*b - L, L, denom);
     }
 
-    if (x > a) {
-       *r = L + SkMulDiv(*r - L, a - L, x - L);
-       *g = L + SkMulDiv(*g - L, a - L, x - L);
-       *b = L + SkMulDiv(*b - L, a - L, x - L);
+    if ((x > a) && (denom = x - L)) { // Compute denom and make sure it's non zero
+       int numer = a - L;
+       *r = L + SkMulDiv(*r - L, numer, denom);
+       *g = L + SkMulDiv(*g - L, numer, denom);
+       *b = L + SkMulDiv(*b - L, numer, denom);
     }
 }
 
@@ -673,12 +676,12 @@ bool SkXfermode::asMode(Mode* mode) const {
     return false;
 }
 
-bool SkXfermode::asNewEffect(GrEffectRef** effect, GrTexture* background) const {
+bool SkXfermode::asNewEffect(GrEffect** effect, GrTexture* background) const {
     return false;
 }
 
 bool SkXfermode::AsNewEffectOrCoeff(SkXfermode* xfermode,
-                                    GrEffectRef** effect,
+                                    GrEffect** effect,
                                     Coeff* src,
                                     Coeff* dst,
                                     GrTexture* background) {
@@ -771,116 +774,6 @@ void SkXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
     }
 }
 
-///////////////////////////////////////////////////////////////////////////////
-
-void SkProcXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
-                            const SkPMColor* SK_RESTRICT src, int count,
-                            const SkAlpha* SK_RESTRICT aa) const {
-    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(uint16_t* SK_RESTRICT dst,
-                            const SkPMColor* SK_RESTRICT src, int count,
-                            const SkAlpha* SK_RESTRICT aa) const {
-    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::xferA8(SkAlpha* SK_RESTRICT dst,
-                            const SkPMColor* SK_RESTRICT src, int count,
-                            const SkAlpha* SK_RESTRICT aa) const {
-    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 = NULL;
-    if (!buffer.isCrossProcess()) {
-        fProc = (SkXfermodeProc)buffer.readFunctionPtr();
-    }
-}
-
-void SkProcXfermode::flatten(SkFlattenableWriteBuffer& buffer) const {
-    this->INHERITED::flatten(buffer);
-    if (!buffer.isCrossProcess()) {
-        buffer.writeFunctionPtr((void*)fProc);
-    }
-}
-
-#ifdef SK_DEVELOPER
-void SkProcXfermode::toString(SkString* str) const {
-    str->appendf("SkProcXfermode: %p", fProc);
-}
-#endif
-
 //////////////////////////////////////////////////////////////////////////////
 
 #if SK_SUPPORT_GPU
@@ -890,6 +783,7 @@ void SkProcXfermode::toString(SkString* str) const {
 #include "GrEffectUnitTest.h"
 #include "GrTBackendEffectFactory.h"
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLShaderBuilder.h"
 
 /**
  * GrEffect that implements the all the separable xfer modes that cannot be expressed as Coeffs.
@@ -900,12 +794,11 @@ public:
         return mode > SkXfermode::kLastCoeffMode && mode <= SkXfermode::kLastMode;
     }
 
-    static GrEffectRef* Create(SkXfermode::Mode mode, GrTexture* background) {
+    static GrEffect* Create(SkXfermode::Mode mode, GrTexture* background) {
         if (!IsSupportedMode(mode)) {
             return NULL;
         } else {
-            AutoEffectUnref effect(SkNEW_ARGS(XferEffect, (mode, background)));
-            return CreateEffectRef(effect);
+            return SkNEW_ARGS(XferEffect, (mode, background));
         }
     }
 
@@ -930,7 +823,7 @@ public:
         }
         virtual void emitCode(GrGLShaderBuilder* builder,
                               const GrDrawEffect& drawEffect,
-                              EffectKey key,
+                              const GrEffectKey& key,
                               const char* outputColor,
                               const char* inputColor,
                               const TransformedCoordsArray& coords,
@@ -1071,13 +964,18 @@ public:
                     break;
                 }
                 default:
-                    GrCrash("Unknown XferEffect mode.");
+                    SkFAIL("Unknown XferEffect mode.");
                     break;
             }
         }
 
-        static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
-            return drawEffect.castEffect<XferEffect>().mode();
+        static inline void GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&,
+                                  GrEffectKeyBuilder* b) {
+            // The background may come from the dst or from a texture.
+            uint32_t key = drawEffect.effect()->numTextures();
+            SkASSERT(key <= 1);
+            key |= drawEffect.castEffect<XferEffect>().mode() << 1;
+            b->add32(key);
         }
 
     private:
@@ -1328,14 +1226,13 @@ private:
 };
 
 GR_DEFINE_EFFECT_TEST(XferEffect);
-GrEffectRef* XferEffect::TestCreate(SkRandom* rand,
-                                    GrContext*,
-                                    const GrDrawTargetCaps&,
-                                    GrTexture*[]) {
+GrEffect* XferEffect::TestCreate(SkRandom* rand,
+                                 GrContext*,
+                                 const GrDrawTargetCaps&,
+                                 GrTexture*[]) {
     int mode = rand->nextRangeU(SkXfermode::kLastCoeffMode + 1, SkXfermode::kLastSeparableMode);
 
-    AutoEffectUnref gEffect(SkNEW_ARGS(XferEffect, (static_cast<SkXfermode::Mode>(mode), NULL)));
-    return CreateEffectRef(gEffect);
+    return SkNEW_ARGS(XferEffect, (static_cast<SkXfermode::Mode>(mode), NULL));
 }
 
 #endif
@@ -1343,6 +1240,21 @@ GrEffectRef* XferEffect::TestCreate(SkRandom* rand,
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
 
+SkProcCoeffXfermode::SkProcCoeffXfermode(SkReadBuffer& buffer) : INHERITED(buffer) {
+    uint32_t mode32 = buffer.read32() % SK_ARRAY_COUNT(gProcCoeffs);
+    if (mode32 >= SK_ARRAY_COUNT(gProcCoeffs)) {
+        // out of range, just set to something harmless
+        mode32 = SkXfermode::kSrcOut_Mode;
+    }
+    fMode = (SkXfermode::Mode)mode32;
+
+    const ProcCoeff& rec = gProcCoeffs[fMode];
+    fProc = rec.fProc;
+    // these may be valid, or may be CANNOT_USE_COEFF
+    fSrcCoeff = rec.fSC;
+    fDstCoeff = rec.fDC;
+}
+
 bool SkProcCoeffXfermode::asMode(Mode* mode) const {
     if (mode) {
         *mode = fMode;
@@ -1364,9 +1276,95 @@ bool SkProcCoeffXfermode::asCoeff(Coeff* sc, Coeff* dc) const {
     return true;
 }
 
+void SkProcCoeffXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
+                                 const SkPMColor* SK_RESTRICT src, int count,
+                                 const SkAlpha* SK_RESTRICT aa) const {
+    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 SkProcCoeffXfermode::xfer16(uint16_t* SK_RESTRICT dst,
+                                 const SkPMColor* SK_RESTRICT src, int count,
+                                 const SkAlpha* SK_RESTRICT aa) const {
+    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 SkProcCoeffXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
+                                 const SkPMColor* SK_RESTRICT src, int count,
+                                 const SkAlpha* SK_RESTRICT aa) const {
+    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);
+                }
+            }
+        }
+    }
+}
+
 #if SK_SUPPORT_GPU
-bool SkProcCoeffXfermode::asNewEffect(GrEffectRef** effect,
-                                      GrTexture* background) const {
+bool SkProcCoeffXfermode::asNewEffect(GrEffect** effect, GrTexture* background) const {
     if (XferEffect::IsSupportedMode(fMode)) {
         if (NULL != effect) {
             *effect = XferEffect::Create(fMode, background);
@@ -1378,7 +1376,7 @@ bool SkProcCoeffXfermode::asNewEffect(GrEffectRef** effect,
 }
 #endif
 
-void SkProcCoeffXfermode::flatten(SkFlattenableWriteBuffer& buffer) const {
+void SkProcCoeffXfermode::flatten(SkWriteBuffer& buffer) const {
     this->INHERITED::flatten(buffer);
     buffer.write32(fMode);
 }
@@ -1396,7 +1394,7 @@ const char* SkXfermode::ModeName(Mode mode) {
     SK_COMPILE_ASSERT(SK_ARRAY_COUNT(gModeStrings) == kLastMode + 1, mode_count);
 }
 
-#ifdef SK_DEVELOPER
+#ifndef SK_IGNORE_TO_STRING
 void SkProcCoeffXfermode::toString(SkString* str) const {
     str->append("SkProcCoeffXfermode: ");
 
@@ -1427,16 +1425,19 @@ void SkProcCoeffXfermode::toString(SkString* str) const {
 
 class SkClearXfermode : public SkProcCoeffXfermode {
 public:
-    SkClearXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kClear_Mode) {}
+    static SkClearXfermode* Create(const ProcCoeff& rec) {
+        return SkNEW_ARGS(SkClearXfermode, (rec));
+    }
 
     virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
     virtual void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
 
-    SK_DEVELOPER_TO_STRING()
+    SK_TO_STRING_OVERRIDE()
     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkClearXfermode)
 
 private:
-    SkClearXfermode(SkFlattenableReadBuffer& buffer)
+    SkClearXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kClear_Mode) {}
+    SkClearXfermode(SkReadBuffer& buffer)
         : SkProcCoeffXfermode(buffer) {}
 
     typedef SkProcCoeffXfermode INHERITED;
@@ -1479,7 +1480,7 @@ void SkClearXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
     }
 }
 
-#ifdef SK_DEVELOPER
+#ifndef SK_IGNORE_TO_STRING
 void SkClearXfermode::toString(SkString* str) const {
     this->INHERITED::toString(str);
 }
@@ -1489,16 +1490,19 @@ void SkClearXfermode::toString(SkString* str) const {
 
 class SkSrcXfermode : public SkProcCoeffXfermode {
 public:
-    SkSrcXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kSrc_Mode) {}
+    static SkSrcXfermode* Create(const ProcCoeff& rec) {
+        return SkNEW_ARGS(SkSrcXfermode, (rec));
+    }
 
     virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
     virtual void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
 
-    SK_DEVELOPER_TO_STRING()
+    SK_TO_STRING_OVERRIDE()
     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSrcXfermode)
 
 private:
-    SkSrcXfermode(SkFlattenableReadBuffer& buffer)
+    SkSrcXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kSrc_Mode) {}
+    SkSrcXfermode(SkReadBuffer& buffer)
         : SkProcCoeffXfermode(buffer) {}
 
     typedef SkProcCoeffXfermode INHERITED;
@@ -1546,7 +1550,7 @@ void SkSrcXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
         }
     }
 }
-#ifdef SK_DEVELOPER
+#ifndef SK_IGNORE_TO_STRING
 void SkSrcXfermode::toString(SkString* str) const {
     this->INHERITED::toString(str);
 }
@@ -1556,15 +1560,18 @@ void SkSrcXfermode::toString(SkString* str) const {
 
 class SkDstInXfermode : public SkProcCoeffXfermode {
 public:
-    SkDstInXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstIn_Mode) {}
+    static SkDstInXfermode* Create(const ProcCoeff& rec) {
+        return SkNEW_ARGS(SkDstInXfermode, (rec));
+    }
 
     virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
 
-    SK_DEVELOPER_TO_STRING()
+    SK_TO_STRING_OVERRIDE()
     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDstInXfermode)
 
 private:
-    SkDstInXfermode(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
+    SkDstInXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstIn_Mode) {}
+    SkDstInXfermode(SkReadBuffer& buffer) : INHERITED(buffer) {}
 
     typedef SkProcCoeffXfermode INHERITED;
 };
@@ -1589,7 +1596,7 @@ void SkDstInXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
     } while (--count != 0);
 }
 
-#ifdef SK_DEVELOPER
+#ifndef SK_IGNORE_TO_STRING
 void SkDstInXfermode::toString(SkString* str) const {
     this->INHERITED::toString(str);
 }
@@ -1599,15 +1606,18 @@ void SkDstInXfermode::toString(SkString* str) const {
 
 class SkDstOutXfermode : public SkProcCoeffXfermode {
 public:
-    SkDstOutXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstOut_Mode) {}
+    static SkDstOutXfermode* Create(const ProcCoeff& rec) {
+        return SkNEW_ARGS(SkDstOutXfermode, (rec));
+    }
 
     virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
 
-    SK_DEVELOPER_TO_STRING()
+    SK_TO_STRING_OVERRIDE()
     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDstOutXfermode)
 
 private:
-    SkDstOutXfermode(SkFlattenableReadBuffer& buffer)
+    SkDstOutXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstOut_Mode) {}
+    SkDstOutXfermode(SkReadBuffer& buffer)
         : INHERITED(buffer) {}
 
     typedef SkProcCoeffXfermode INHERITED;
@@ -1633,7 +1643,7 @@ void SkDstOutXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
     } while (--count != 0);
 }
 
-#ifdef SK_DEVELOPER
+#ifndef SK_IGNORE_TO_STRING
 void SkDstOutXfermode::toString(SkString* str) const {
     this->INHERITED::toString(str);
 }
@@ -1641,76 +1651,72 @@ void SkDstOutXfermode::toString(SkString* str) const {
 
 ///////////////////////////////////////////////////////////////////////////////
 
-SK_DECLARE_STATIC_MUTEX(gCachedXfermodesMutex);
-static SkXfermode* gCachedXfermodes[SkXfermode::kLastMode + 1];
+extern SkProcCoeffXfermode* SkPlatformXfermodeFactory(const ProcCoeff& rec, SkXfermode::Mode mode);
+extern SkXfermodeProc SkPlatformXfermodeProcFactory(SkXfermode::Mode mode);
 
-void SkXfermode::Term() {
-    SkAutoMutexAcquire ac(gCachedXfermodesMutex);
+// Technically, can't be static and passed as a template parameter.  So we use anonymous namespace.
+namespace {
+SkXfermode* create_mode(int iMode) {
+    SkXfermode::Mode mode = (SkXfermode::Mode)iMode;
 
-    for (size_t i = 0; i < SK_ARRAY_COUNT(gCachedXfermodes); ++i) {
-        SkSafeUnref(gCachedXfermodes[i]);
-        gCachedXfermodes[i] = NULL;
+    ProcCoeff rec = gProcCoeffs[mode];
+    SkXfermodeProc pp = SkPlatformXfermodeProcFactory(mode);
+    if (pp != NULL) {
+        rec.fProc = pp;
     }
+
+    SkXfermode* xfer = NULL;
+    // check if we have a platform optim for that
+    SkProcCoeffXfermode* xfm = SkPlatformXfermodeFactory(rec, mode);
+    if (xfm != NULL) {
+        xfer = xfm;
+    } else {
+        // All modes can in theory be represented by the ProcCoeff rec, since
+        // it contains function ptrs. However, a few modes are both simple and
+        // commonly used, so we call those out for their own subclasses here.
+        switch (mode) {
+            case SkXfermode::kClear_Mode:
+                xfer = SkClearXfermode::Create(rec);
+                break;
+            case SkXfermode::kSrc_Mode:
+                xfer = SkSrcXfermode::Create(rec);
+                break;
+            case SkXfermode::kSrcOver_Mode:
+                SkASSERT(false);    // should not land here
+                break;
+            case SkXfermode::kDstIn_Mode:
+                xfer = SkDstInXfermode::Create(rec);
+                break;
+            case SkXfermode::kDstOut_Mode:
+                xfer = SkDstOutXfermode::Create(rec);
+                break;
+            default:
+                // no special-case, just rely in the rec and its function-ptrs
+                xfer = SkProcCoeffXfermode::Create(rec, mode);
+                break;
+        }
+    }
+    return xfer;
 }
+}  // namespace
 
-extern SkProcCoeffXfermode* SkPlatformXfermodeFactory(const ProcCoeff& rec,
-                                                      SkXfermode::Mode mode);
 
 SkXfermode* SkXfermode::Create(Mode mode) {
     SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
-    SkASSERT(SK_ARRAY_COUNT(gCachedXfermodes) == kModeCount);
 
     if ((unsigned)mode >= kModeCount) {
         // report error
         return NULL;
     }
 
-    // Skia's "defaut" mode is srcover. NULL in SkPaint is interpreted as srcover
+    // Skia's "default" mode is srcover. NULL in SkPaint is interpreted as srcover
     // so we can just return NULL from the factory.
     if (kSrcOver_Mode == mode) {
         return NULL;
     }
 
-    // guard our access to gCachedXfermodes, since we may write into it
-    SkAutoMutexAcquire ac(gCachedXfermodesMutex);
-
-    SkXfermode* xfer = gCachedXfermodes[mode];
-    if (NULL == xfer) {
-        const ProcCoeff& rec = gProcCoeffs[mode];
-
-        // check if we have a platform optim for that
-        SkProcCoeffXfermode* xfm = SkPlatformXfermodeFactory(rec, mode);
-        if (xfm != NULL) {
-            xfer = xfm;
-        } else {
-            // All modes can in theory be represented by the ProcCoeff rec, since
-            // it contains function ptrs. However, a few modes are both simple and
-            // commonly used, so we call those out for their own subclasses here.
-            switch (mode) {
-                case kClear_Mode:
-                    xfer = SkNEW_ARGS(SkClearXfermode, (rec));
-                    break;
-                case kSrc_Mode:
-                    xfer = SkNEW_ARGS(SkSrcXfermode, (rec));
-                    break;
-                case kSrcOver_Mode:
-                    SkASSERT(false);    // should not land here
-                    break;
-                case kDstIn_Mode:
-                    xfer = SkNEW_ARGS(SkDstInXfermode, (rec));
-                    break;
-                case kDstOut_Mode:
-                    xfer = SkNEW_ARGS(SkDstOutXfermode, (rec));
-                    break;
-                default:
-                    // no special-case, just rely in the rec and its function-ptrs
-                    xfer = SkNEW_ARGS(SkProcCoeffXfermode, (rec, mode));
-                    break;
-            }
-        }
-        gCachedXfermodes[mode] = xfer;
-    }
-    return SkSafeRef(xfer);
+    SK_DECLARE_STATIC_LAZY_PTR_ARRAY(SkXfermode, cached, kModeCount, create_mode);
+    return SkSafeRef(cached[mode]);
 }
 
 SkXfermodeProc SkXfermode::GetProc(Mode mode) {
@@ -1953,4 +1959,7 @@ SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkXfermode)
 #if !SK_ARM_NEON_IS_NONE
     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkNEONProcCoeffXfermode)
 #endif
+#if defined(SK_CPU_X86) && !defined(SK_BUILD_FOR_IOS)
+    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSSE2ProcCoeffXfermode)
+#endif
 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END