add unit test for clamp-before-premul

Bug: chromium:867813
Bug: chromium:862908

Change-Id: I79a82b6637c8a707844642b9bce4444bb85828b5
Reviewed-on: https://skia-review.googlesource.com/144295
Auto-Submit: Mike Klein <mtklein@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/skcms.cc b/skcms.cc
index 3595088..6fb4af9 100644
--- a/skcms.cc
+++ b/skcms.cc
@@ -2230,7 +2230,6 @@
     //
     // E.g. r = 1.1, a = 0.5 would fit fine in fixed point after premul (ra=0.55,a=0.5),
     // but would be carrying r > 1, which is really unexpected for downstream consumers.
-    // TODO(mtklein): add a unit test
     if (dstFmt < skcms_PixelFormat_RGB_hhh) {
         *ops++ = Op_clamp;
     }
diff --git a/tests.c b/tests.c
index 09669f7..cef8ea9 100644
--- a/tests.c
+++ b/tests.c
@@ -1086,6 +1086,46 @@
     expect(skcms_ApproximatelyEqualProfiles(&p, &srgb));
 }
 
+static void test_Clamp() {
+    // Test that we clamp out-of-gamut values when converting to fixed point,
+    // not just to byte value range but also to gamut (for compatibility with
+    // older systems).
+
+    void*  dp3_ptr;
+    size_t dp3_len;
+    expect(load_file("profiles/mobile/Display_P3_parametric.icc", &dp3_ptr, &dp3_len));
+
+    // Here's the basic premise of the test: sRGB can't represent P3's full green,
+    // but if we scale it by 50% alpha, it would "fit" in a byte.  We want to avoid that.
+    skcms_ICCProfile src,
+                     dst = *skcms_sRGB_profile();
+    skcms_Parse(dp3_ptr, dp3_len, &src);
+    uint8_t rgba[] = { 0, 255, 0, 127 };
+
+    // First double check that the green channel is out of gamut by transforming to float.
+    float flts[4];
+    skcms_Transform(rgba, skcms_PixelFormat_RGBA_8888, skcms_AlphaFormat_Unpremul, &src,
+                    flts, skcms_PixelFormat_RGBA_ffff, skcms_AlphaFormat_Unpremul, &dst,
+                    1);
+    expect(flts[0] < 0);   // A typical out-of-gamut green.  r,b are negative, and g > 1.
+    expect(flts[1] > 1);
+    expect(flts[2] < 0);
+    expect(flts[3] == 127*(1/255.0f));
+
+    // Now the real test, making sure we clamp that green channel to 1.0 before premul.
+    skcms_Transform(rgba, skcms_PixelFormat_RGBA_8888, skcms_AlphaFormat_Unpremul       , &src,
+                    rgba, skcms_PixelFormat_RGBA_8888, skcms_AlphaFormat_PremulAsEncoded, &dst,
+                    1);
+
+    expect(rgba[0] ==   0);
+    expect(rgba[1] == 127);  // would be 129 if we clamped after premul
+    expect(rgba[2] ==   0);
+    expect(rgba[3] == 127);
+
+
+    free(dp3_ptr);
+}
+
 int main(int argc, char** argv) {
     bool regenTestData = false;
     for (int i = 1; i < argc; ++i) {
@@ -1115,6 +1155,7 @@
     test_MakeUsableAsDestinationAdobe();
     test_PrimariesToXYZ();
     test_Programmatic_sRGB();
+    test_Clamp();
 #if 0
     test_CLUT();
 #endif