Reland "add getAlphaf() to pixmap/bitmap"

This is a reland of f3ebd312f21325f9afc4479fd7a4e90a32ffb920

PS 2: use faster half->float routine
PS 3: relax tolerance to 2^-10 for half, keeping others 2^-12

Original change's description:
> add getAlphaf() to pixmap/bitmap
>
> Convenient for just extracting alpha (and more efficient than getColor()) and
> works for super-normal formats w/o loss of precision.
>
> Somewhat inspired by examining multiple chrome call-sites for getColor(), where
> chrome only really cared about the alpha. This new method runs about twice
> as fast as getColor() for the simple cases (i.e. no colorspace xforms), and
> even faster in the complex cases (since retrieving alpha doesn't care about
> colorspaces).
>
> Bug: skia:
> Change-Id: I7cd5a2c7f78de781aaa69dd1aa0dba3c532fcb73
> Reviewed-on: https://skia-review.googlesource.com/155606
> Commit-Queue: Mike Reed <reed@google.com>
> Reviewed-by: Mike Klein <mtklein@google.com>

Cq-Include-Trybots: skia.primary:Test-Android-Clang-Nexus7-CPU-Tegra3-arm-Debug-All-Android,Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Release-All-SK_CPU_LIMIT_SSE2,Test-Debian9-GCC-GCE-CPU-AVX2-x86_64-Release-All,Test-Win2016-MSVC-GCE-CPU-AVX2-x86_64-Release-All,Test-Win8-Clang-Golo-CPU-AVX-x86_64-Debug-All
Bug: skia:
Change-Id: Ie94e5c89e185fde12cbd6c56ed4026c4dc5a1623
Reviewed-on: https://skia-review.googlesource.com/156242
Commit-Queue: Ravi Mistry <rmistry@google.com>
Commit-Queue: Mike Klein <mtklein@google.com>
Reviewed-by: Mike Klein <mtklein@google.com>
diff --git a/tests/BitmapTest.cpp b/tests/BitmapTest.cpp
index 439136d..70dde59 100644
--- a/tests/BitmapTest.cpp
+++ b/tests/BitmapTest.cpp
@@ -263,3 +263,103 @@
         REPORTER_ASSERT(r, bm.getColor(0,0) != 0x00000000);
     }
 }
+
+static void check_alphas(skiatest::Reporter* reporter, const SkBitmap& bm,
+                         bool (*pred)(float expected, float actual)) {
+    SkASSERT(bm.width() == 16);
+    SkASSERT(bm.height() == 16);
+
+    int alpha = 0;
+    for (int y = 0; y < 16; ++y) {
+        for (int x = 0; x < 16; ++x) {
+            float expected = alpha / 255.0f;
+            float actual = bm.getAlphaf(x, y);
+            if (!pred(expected, actual)) {
+                ERRORF(reporter, "got %g, want %g\n", actual, expected);
+            }
+            alpha += 1;
+        }
+    }
+}
+
+static bool unit_compare(float expected, float actual, float tol = 1.0f/(1<<12)) {
+    SkASSERT(expected >= 0 && expected <= 1);
+    SkASSERT(  actual >= 0 &&   actual <= 1);
+    if (expected == 0 || expected == 1) {
+        return actual == expected;
+    } else {
+        return SkScalarNearlyEqual(expected, actual, tol);
+    }
+}
+
+static float unit_discretize(float value, float scale) {
+    SkASSERT(value >= 0 && value <= 1);
+    if (value == 1) {
+        return 1;
+    } else {
+        return sk_float_floor(value * scale + 0.5f) / scale;
+    }
+}
+
+DEF_TEST(getalphaf, reporter) {
+    SkImageInfo info = SkImageInfo::MakeN32Premul(16, 16);
+    SkBitmap bm;
+    bm.allocPixels(info);
+
+    int alpha = 0;
+    for (int y = 0; y < 16; ++y) {
+        for (int x = 0; x < 16; ++x) {
+            *bm.getAddr32(x, y) = alpha++ << 24;
+        }
+    }
+
+    auto nearly = [](float expected, float actual) -> bool {
+        return unit_compare(expected, actual);
+    };
+    auto nearly4bit = [](float expected, float actual) -> bool {
+        expected = unit_discretize(expected, 15);
+        return unit_compare(expected, actual);
+    };
+    auto nearly2bit = [](float expected, float actual) -> bool {
+        expected = unit_discretize(expected, 3);
+        return unit_compare(expected, actual);
+    };
+    auto opaque = [](float expected, float actual) -> bool {
+        return actual == 1.0f;
+    };
+
+    auto nearly_half = [](float expected, float actual) -> bool {
+        return unit_compare(expected, actual, 1.0f/(1<<10));
+    };
+
+    const struct {
+        SkColorType fColorType;
+        bool (*fPred)(float, float);
+    } recs[] = {
+        { kRGB_565_SkColorType,     opaque },
+        { kGray_8_SkColorType,      opaque },
+        { kRGB_888x_SkColorType,    opaque },
+        { kRGB_101010x_SkColorType, opaque },
+
+        { kAlpha_8_SkColorType,     nearly },
+        { kRGBA_8888_SkColorType,   nearly },
+        { kBGRA_8888_SkColorType,   nearly },
+        { kRGBA_F16_SkColorType,    nearly_half },
+        { kRGBA_F32_SkColorType,    nearly },
+
+        { kRGBA_1010102_SkColorType, nearly2bit },
+
+        { kARGB_4444_SkColorType,   nearly4bit },
+    };
+
+    for (const auto& rec : recs) {
+        SkBitmap tmp;
+        tmp.allocPixels(bm.info().makeColorType(rec.fColorType));
+        if (bm.readPixels(tmp.pixmap())) {
+            check_alphas(reporter, tmp, rec.fPred);
+        } else {
+            SkDebugf("can't readpixels\n");
+        }
+    }
+}
+