land https://codereview.appspot.com/7221086/ -- add Multiply xfermode matching CSS spec



git-svn-id: http://skia.googlecode.com/svn/trunk@7553 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gm/xfermodes.cpp b/gm/xfermodes.cpp
index 9eb2f87..a5baeb9 100644
--- a/gm/xfermodes.cpp
+++ b/gm/xfermodes.cpp
@@ -113,6 +113,7 @@
             { SkXfermode::kSoftLight_Mode,    "SoftLight"     },
             { SkXfermode::kDifference_Mode,   "Difference"    },
             { SkXfermode::kExclusion_Mode,    "Exclusion"     },
+            { SkXfermode::kMultiply_Mode,     "Multiply"      },
         };
 
         const SkScalar w = SkIntToScalar(W);
diff --git a/include/core/SkXfermode.h b/include/core/SkXfermode.h
index d396529..27a6bf3 100644
--- a/include/core/SkXfermode.h
+++ b/include/core/SkXfermode.h
@@ -118,8 +118,9 @@
         kSoftLight_Mode,
         kDifference_Mode,
         kExclusion_Mode,
+        kMultiply_Mode,
 
-        kLastMode = kExclusion_Mode
+        kLastMode = kMultiply_Mode
     };
 
     /**
diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp
index 520ab87..c0a825c 100644
--- a/src/core/SkXfermode.cpp
+++ b/src/core/SkXfermode.cpp
@@ -191,10 +191,28 @@
     return SkPackARGB32(a, r, g, b);
 }
 
-// kScreen_Mode
 static inline int srcover_byte(int a, int b) {
     return a + b - SkAlphaMulAlpha(a, b);
 }
+
+// kMultiply_Mode
+// B(Cb, Cs) = Cb x Cs
+// multiply uses its own version of blendfunc_byte because sa and da are not needed
+static int blendfunc_multiply_byte(int sc, int dc, int sa, int da) {
+    return clamp_div255round(sc * (255 - da)  + dc * (255 - sa)  + sc * dc);
+}
+
+static SkPMColor multiply_modeproc(SkPMColor src, SkPMColor dst) {
+    int sa = SkGetPackedA32(src);
+    int da = SkGetPackedA32(dst);
+    int a = srcover_byte(sa, da);
+    int r = blendfunc_multiply_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
+    int g = blendfunc_multiply_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
+    int b = blendfunc_multiply_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
+    return SkPackARGB32(a, r, g, b);
+}
+
+// kScreen_Mode
 static SkPMColor screen_modeproc(SkPMColor src, SkPMColor dst) {
     int a = srcover_byte(SkGetPackedA32(src), SkGetPackedA32(dst));
     int r = srcover_byte(SkGetPackedR32(src), SkGetPackedR32(dst));
@@ -447,6 +465,7 @@
     { softlight_modeproc,   CANNOT_USE_COEFF,       CANNOT_USE_COEFF },
     { difference_modeproc,  CANNOT_USE_COEFF,       CANNOT_USE_COEFF },
     { exclusion_modeproc,   CANNOT_USE_COEFF,       CANNOT_USE_COEFF },
+    { multiply_modeproc,    CANNOT_USE_COEFF,       CANNOT_USE_COEFF },
 };
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/src/effects/SkBlendImageFilter.cpp b/src/effects/SkBlendImageFilter.cpp
index 3f6d3c5..6da3764 100644
--- a/src/effects/SkBlendImageFilter.cpp
+++ b/src/effects/SkBlendImageFilter.cpp
@@ -19,24 +19,24 @@
 
 namespace {
 
-SkXfermode::Mode modeToXfermode(SkBlendImageFilter::Mode mode)
-{
+SkXfermode::Mode modeToXfermode(SkBlendImageFilter::Mode mode) {
     switch (mode) {
-      case SkBlendImageFilter::kNormal_Mode:
-        return SkXfermode::kSrcOver_Mode;
-      case SkBlendImageFilter::kMultiply_Mode:
-        return SkXfermode::kModulate_Mode;
-      case SkBlendImageFilter::kScreen_Mode:
-        return SkXfermode::kScreen_Mode;
-      case SkBlendImageFilter::kDarken_Mode:
-        return SkXfermode::kDarken_Mode;
-      case SkBlendImageFilter::kLighten_Mode:
-        return SkXfermode::kLighten_Mode;
+        case SkBlendImageFilter::kNormal_Mode:
+            return SkXfermode::kSrcOver_Mode;
+        case SkBlendImageFilter::kMultiply_Mode:
+            return SkXfermode::kMultiply_Mode;
+        case SkBlendImageFilter::kScreen_Mode:
+            return SkXfermode::kScreen_Mode;
+        case SkBlendImageFilter::kDarken_Mode:
+            return SkXfermode::kDarken_Mode;
+        case SkBlendImageFilter::kLighten_Mode:
+            return SkXfermode::kLighten_Mode;
     }
     SkASSERT(0);
     return SkXfermode::kSrcOver_Mode;
 }
 
+#ifdef SK_IGNORE_MULTIPLY_XFERMODE_OPT
 SkPMColor multiply_proc(SkPMColor src, SkPMColor dst) {
     int omsa = 255 - SkGetPackedA32(src);
     int sr = SkGetPackedR32(src), sg = SkGetPackedG32(src), sb = SkGetPackedB32(src);
@@ -48,6 +48,7 @@
     int b = SkMulDiv255Round(omsa, db) + SkMulDiv255Round(omda, sb) + SkMulDiv255Round(sb, db);
     return SkPackARGB32(a, r, g, b);
 }
+#endif
 
 };
 
@@ -97,6 +98,7 @@
     SkPaint paint;
     paint.setXfermodeMode(SkXfermode::kSrc_Mode);
     canvas.drawBitmap(background, 0, 0, &paint);
+#ifdef SK_IGNORE_MULTIPLY_XFERMODE_OPT
     // FEBlend's multiply mode is (1 - Sa) * Da + (1 - Da) * Sc + Sc * Dc
     // Skia's is just Sc * Dc.  So we use a custom proc to implement FEBlend's
     // version.
@@ -105,6 +107,9 @@
     } else {
         paint.setXfermodeMode(modeToXfermode(fMode));
     }
+#else
+    paint.setXfermodeMode(modeToXfermode(fMode));
+#endif
     canvas.drawBitmap(foreground, 0, 0, &paint);
     return true;
 }