Replace buggy_blend_modes GM with an exhaustive test.

The new test is disabled by default, as it's quite slow.
We can run it if we suspect problems by passing -x to DM.

This test would have been failing before the bug fix, and now is passing.

Assuming the Priv on the end means it's not considered public API...
TBR=reed@google.com

BUG=skia:4052

Review URL: https://codereview.chromium.org/1228333003
diff --git a/gm/buggy_blend_modes.cpp b/gm/buggy_blend_modes.cpp
deleted file mode 100644
index 21a6798..0000000
--- a/gm/buggy_blend_modes.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkCanvas.h"
-#include "SkGradientShader.h"
-#include "gm.h"
-
-// This GM reproduces what I think are overflow bugs in the CPU implementations of a
-// couple xfermodes.  I've marked non-obvious keys to reproducing the bug // Essential!
-DEF_SIMPLE_GM(buggy_blend_modes, canvas, 800, 200) {
-    const auto tiling = SkShader::kClamp_TileMode;
-    const auto flags = SkGradientShader::kInterpolateColorsInPremul_Flag;  // Essential!
-
-    SkAutoTUnref<SkShader> cyanH, magentaV;
-    {
-        SkPoint    pts[] = { {0,0}, {200, 0} };
-        SkColor colors[] = { 0x00000000, 0xFF00FFFF };
-        cyanH.reset(
-                SkGradientShader::CreateLinear(pts, colors, nullptr, 2, tiling, flags, nullptr));
-    }
-    {
-        SkPoint    pts[] = { {0,0}, {0, 200} };
-        SkColor colors[] = { 0x00000000, 0xFFFF00FF };
-        magentaV.reset(
-                SkGradientShader::CreateLinear(pts, colors, nullptr, 2, tiling, flags, nullptr));
-    }
-
-    SkXfermode::Mode modes[] = {
-        SkXfermode::kDarken_Mode,       // Looks ok?
-        SkXfermode::kHardLight_Mode,    // Definitely wrong.
-        SkXfermode::kLighten_Mode,      // Definitely wrong.
-        SkXfermode::kOverlay_Mode,      // Same code as kHardLight_Mode.
-    };
-
-    canvas->clear(SK_ColorWHITE);
-    for (auto mode : modes) {
-        canvas->saveLayer(nullptr, nullptr);  // Essential!
-            SkPaint h, v;
-            h.setShader(cyanH);
-            v.setShader(magentaV);
-            v.setXfermodeMode(mode);
-            canvas->drawRect(SkRect::MakeWH(200,200), h);
-            canvas->drawRect(SkRect::MakeWH(200,200), v);
-        canvas->restore();
-
-        canvas->translate(200, 0);
-    }
-}
diff --git a/include/core/SkColorPriv.h b/include/core/SkColorPriv.h
index 15c94ac..f9c5d92 100644
--- a/include/core/SkColorPriv.h
+++ b/include/core/SkColorPriv.h
@@ -369,6 +369,18 @@
     #define SkPMColorAssert(c)
 #endif
 
+static inline bool SkPMColorValid(SkPMColor c) {
+    auto a = SkGetPackedA32(c);
+    bool valid = a <= SK_A32_MASK
+              && SkGetPackedR32(c) <= a
+              && SkGetPackedG32(c) <= a
+              && SkGetPackedB32(c) <= a;
+    if (valid) {
+        SkPMColorAssert(c);  // Make sure we're consistent when it counts.
+    }
+    return valid;
+}
+
 /**
  *  Pack the components into a SkPMColor, checking (in the debug version) that
  *  the components are 0..255, and are already premultiplied (i.e. alpha >= color)
diff --git a/tests/BlendTest.cpp b/tests/BlendTest.cpp
index a0a84d7..d816b72 100644
--- a/tests/BlendTest.cpp
+++ b/tests/BlendTest.cpp
@@ -1,5 +1,15 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
 #include "Test.h"
 #include "SkColor.h"
+#include "SkColorPriv.h"
+#include "SkTaskGroup.h"
+#include "SkXfermode.h"
 
 #define ASSERT(x) REPORTER_ASSERT(r, x)
 
@@ -256,3 +266,36 @@
 //  all others
 //
 //  Algorithms that make sense to use in Skia: blend_256_round, blend_256_round_alt, blend_perfect
+
+DEF_TEST(Blend_premul_begets_premul, r) {
+    // This test is quite slow, even if you have enough cores to run each mode in parallel.
+    if (!r->allowExtendedTest()) {
+        return;
+    }
+
+    // No matter what xfermode we use, premul inputs should create premul outputs.
+    auto test_mode = [&](int m) {
+        SkXfermode::Mode mode = (SkXfermode::Mode)m;
+        if (mode == SkXfermode::kSrcOver_Mode) {
+            return;  // TODO: can't create a SrcOver xfermode.
+        }
+        SkAutoTUnref<SkXfermode> xfermode(SkXfermode::Create(mode));
+        SkASSERT(xfermode);
+        // We'll test all alphas and legal color values, assuming all colors work the same.
+        // This is not true for non-separable blend modes, but this test still can't hurt.
+        for (int sa = 0; sa <= 255; sa++) {
+        for (int da = 0; da <= 255; da++) {
+        for (int  s = 0;  s <= sa;   s++) {
+        for (int  d = 0;  d <= da;   d++) {
+            SkPMColor src = SkPackARGB32(sa, s, s, s),
+                      dst = SkPackARGB32(da, d, d, d);
+            xfermode->xfer32(&dst, &src, 1, nullptr);  // To keep it simple, no AA.
+            if (!SkPMColorValid(dst)) {
+                ERRORF(r, "%08x is not premul using %s", dst, SkXfermode::ModeName(mode));
+            }
+        }}}}
+    };
+
+    // Parallelism helps speed things up on my desktop from ~725s to ~50s.
+    sk_parallel_for(SkXfermode::kLastMode, test_mode);
+}