remove profile.tf, use profile.trc[0-2] instead

Change-Id: Ie12a02832a6e1ec105fa587af4b93c2e0bf8055f
Reviewed-on: https://skia-review.googlesource.com/112160
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Mike Klein <mtklein@chromium.org>
diff --git a/skcms.h b/skcms.h
index d233484..7fac666 100644
--- a/skcms.h
+++ b/skcms.h
@@ -107,12 +107,6 @@
 
     // skcms_Parse() will set commonly-used fields for you when possible:
 
-    // If the transfer functions for all color channels in this profile are
-    // identical and can be represented by a single skcms_TransferFunction,
-    // skcms_Parse() sets tf to that function and has_tf to true.
-    bool                   has_tf;
-    skcms_TransferFunction tf;
-
     // If we can parse red, green and blue transfer curves from the profile,
     // trc will be set to those three curves, and has_trc will be true.
     bool                   has_trc;
diff --git a/src/ICCProfile.c b/src/ICCProfile.c
index cf0cc5b..71381dd 100644
--- a/src/ICCProfile.c
+++ b/src/ICCProfile.c
@@ -285,26 +285,6 @@
     return false;
 }
 
-static bool get_transfer_function(const skcms_ICCProfile* profile,
-                                  skcms_TransferFunction* transferFunction) {
-    if (!profile->has_trc) {
-        return false;
-    }
-
-    const skcms_Curve* trc = profile->trc;
-    if (trc[0].table_entries || trc[1].table_entries || trc[2].table_entries) {
-        return false;
-    }
-
-    if (0 != memcmp(&trc[0].parametric, &trc[1].parametric, SAFE_SIZEOF(trc[0].parametric)) ||
-        0 != memcmp(&trc[0].parametric, &trc[2].parametric, SAFE_SIZEOF(trc[0].parametric))) {
-        return false;
-    }
-
-    *transferFunction = trc[0].parametric;
-    return true;
-}
-
 bool skcms_ApproximateTransferFunction(const skcms_ICCProfile* profile,
                                        skcms_TransferFunction* fn,
                                        float* max_error) {
@@ -788,8 +768,6 @@
         profile->has_trc = true;
     }
 
-    profile->has_tf       = get_transfer_function(profile, &profile->tf);
-
     skcms_ICCTag rXYZ, gXYZ, bXYZ;
     if (skcms_GetTagBySignature(profile, make_signature('r', 'X', 'Y', 'Z'), &rXYZ) &&
         skcms_GetTagBySignature(profile, make_signature('g', 'X', 'Y', 'Z'), &gXYZ) &&
diff --git a/src/Transform.c b/src/Transform.c
index 9635e11..575ac50 100644
--- a/src/Transform.c
+++ b/src/Transform.c
@@ -741,13 +741,21 @@
     next_stage(i,ip,ctx, r,g,b,a);
 }
 
-static void transfer_function(int i, void** ip, Context* ctx, F r, F g, F b, F a) {
+static void transfer_function_r(int i, void** ip, Context* ctx, F r, F g, F b, F a) {
     const skcms_TransferFunction* tf = *ctx->args++;
-
     r = apply_transfer_function(tf, r);
-    g = apply_transfer_function(tf, g);
-    b = apply_transfer_function(tf, b);
+    next_stage(i,ip,ctx, r,g,b,a);
+}
 
+static void transfer_function_g(int i, void** ip, Context* ctx, F r, F g, F b, F a) {
+    const skcms_TransferFunction* tf = *ctx->args++;
+    g = apply_transfer_function(tf, g);
+    next_stage(i,ip,ctx, r,g,b,a);
+}
+
+static void transfer_function_b(int i, void** ip, Context* ctx, F r, F g, F b, F a) {
+    const skcms_TransferFunction* tf = *ctx->args++;
+    b = apply_transfer_function(tf, b);
     next_stage(i,ip,ctx, r,g,b,a);
 }
 
@@ -780,6 +788,13 @@
     return 0;
 }
 
+static bool is_parametric(const skcms_ICCProfile* profile) {
+    return profile->has_trc
+        && profile->trc[0].table_entries == 0
+        && profile->trc[1].table_entries == 0
+        && profile->trc[2].table_entries == 0;
+}
+
 bool skcms_Transform(const void* src, skcms_PixelFormat srcFmt, const skcms_ICCProfile* srcProfile,
                            void* dst, skcms_PixelFormat dstFmt, const skcms_ICCProfile* dstProfile,
                      size_t nz) {
@@ -809,7 +824,7 @@
     void**       ip   = program;
     const void** args = arguments;
 
-    skcms_TransferFunction inv_dst_tf;
+    skcms_TransferFunction inv_dst_tf_r, inv_dst_tf_g, inv_dst_tf_b;
     skcms_Matrix3x3        from_xyz;
 
     switch (srcFmt >> 1) {
@@ -835,9 +850,11 @@
         // TODO: A2B, Lab -> XYZ, tables, etc...
 
         // 1) Src RGB to XYZ
-        if (srcProfile->has_tf && srcProfile->has_toXYZD50) {
-            *ip++ = (void*)transfer_function; *args++ = &srcProfile->tf;
-            *ip++ = (void*)matrix_3x3;        *args++ = &srcProfile->toXYZD50;
+        if (is_parametric(srcProfile) && srcProfile->has_toXYZD50) {
+            *ip++ = (void*)transfer_function_r; *args++ = &srcProfile->trc[0].parametric;
+            *ip++ = (void*)transfer_function_g; *args++ = &srcProfile->trc[1].parametric;
+            *ip++ = (void*)transfer_function_b; *args++ = &srcProfile->trc[2].parametric;
+            *ip++ = (void*)matrix_3x3;          *args++ = &srcProfile->toXYZD50;
         } else {
             return false;
         }
@@ -845,12 +862,16 @@
         // 2) Lab <-> XYZ (if PCS is different)
 
         // 3) Dst XYZ to RGB
-        if (dstProfile->has_tf &&
+        if (is_parametric(dstProfile) &&
+            skcms_TransferFunction_invert(&dstProfile->trc[0].parametric, &inv_dst_tf_r) &&
+            skcms_TransferFunction_invert(&dstProfile->trc[1].parametric, &inv_dst_tf_g) &&
+            skcms_TransferFunction_invert(&dstProfile->trc[2].parametric, &inv_dst_tf_b) &&
             dstProfile->has_toXYZD50 &&
-            skcms_TransferFunction_invert(&dstProfile->tf, &inv_dst_tf) &&
             skcms_Matrix3x3_invert(&dstProfile->toXYZD50,  &from_xyz)) {
-            *ip++ = (void*)matrix_3x3;        *args++ = &from_xyz;
-            *ip++ = (void*)transfer_function; *args++ = &inv_dst_tf;
+            *ip++ = (void*)matrix_3x3;          *args++ = &from_xyz;
+            *ip++ = (void*)transfer_function_r; *args++ = &inv_dst_tf_r;
+            *ip++ = (void*)transfer_function_g; *args++ = &inv_dst_tf_g;
+            *ip++ = (void*)transfer_function_b; *args++ = &inv_dst_tf_b;
         } else {
             return false;
         }
diff --git a/test_only.c b/test_only.c
index 96c4d50..71b355c 100644
--- a/test_only.c
+++ b/test_only.c
@@ -10,9 +10,10 @@
 #endif
 
 #include "skcms.h"
-#include "test_only.h"
 #include "src/TransferFunction.h"
+#include "test_only.h"
 #include <stdlib.h>
+#include <string.h>
 
 static void signature_to_string(uint32_t sig, char* str) {
     str[0] = (char)((sig >> 24) & 0xFF);
@@ -47,6 +48,25 @@
     }
 }
 
+static bool has_single_transfer_function(const skcms_ICCProfile* profile,
+                                         skcms_TransferFunction* tf) {
+    const skcms_Curve* trc = profile->trc;
+    if (profile->has_trc &&
+            trc[0].table_entries == 0 &&
+            trc[1].table_entries == 0 &&
+            trc[2].table_entries == 0) {
+
+        if (0 != memcmp(&trc[0].parametric, &trc[1].parametric, sizeof(skcms_TransferFunction)) ||
+            0 != memcmp(&trc[0].parametric, &trc[2].parametric, sizeof(skcms_TransferFunction))) {
+            return false;
+        }
+
+        memcpy(tf, &trc[0].parametric, sizeof(skcms_TransferFunction));
+        return true;
+    }
+    return false;
+}
+
 void dump_profile(const skcms_ICCProfile* profile, FILE* fp, bool for_unit_test) {
     fprintf(fp, "%20s : 0x%08X : %u\n", "Size", profile->size, profile->size);
     dump_sig_field(fp, "CMM type", profile->cmm_type);
@@ -94,9 +114,11 @@
     fprintf(fp, "\n");
 
     skcms_TransferFunction tf;
+    bool has_single_tf = has_single_transfer_function(profile, &tf);
+
     float max_error;
-    if (profile->has_tf) {
-        dump_transfer_function(fp, "TRC", &profile->tf);
+    if (has_single_tf) {
+        dump_transfer_function(fp, "TRC", &tf);
     } else if (skcms_ApproximateTransferFunction(profile, &tf, &max_error)) {
         if (for_unit_test) {
             // The approximated transfer function can vary significantly, due to FMA, etc. In unit
@@ -113,7 +135,7 @@
         }
     }
 
-    if (!profile->has_tf && profile->has_trc) {
+    if (!has_single_tf && profile->has_trc) {
         const char* trcNames[3] = { "rTRC", "gTRC", "bTRC" };
         for (int i = 0; i < 3; ++i) {
             dump_curve(fp, trcNames[i], &profile->trc[i]);
diff --git a/tests.c b/tests.c
index 0034238..cadde07 100644
--- a/tests.c
+++ b/tests.c
@@ -892,16 +892,16 @@
     skcms_ICCProfile p;
 
     expect( load_file("profiles/mobile/sRGB_parametric.icc", &ptr, &len) );
-    expect( skcms_Parse(ptr, len, &p) && p.has_tf && skcms_IsSRGB(&p.tf) );
+    expect( skcms_Parse(ptr, len, &p) && p.has_trc && skcms_IsSRGB(&p.trc[0].parametric) );
     free(ptr);
 
     expect( load_file("profiles/mobile/Display_P3_parametric.icc", &ptr, &len) );
-    expect( skcms_Parse(ptr, len, &p) && p.has_tf && skcms_IsSRGB(&p.tf) );
+    expect( skcms_Parse(ptr, len, &p) && p.has_trc && skcms_IsSRGB(&p.trc[0].parametric) );
     free(ptr);
 
     // TODO: relax skcms_IsSRGB() so that this one is seen as sRGB too?  It's not far.
     expect( load_file("profiles/mobile/iPhone7p.icc", &ptr, &len) );
-    expect( skcms_Parse(ptr, len, &p) && p.has_tf && !skcms_IsSRGB(&p.tf) );
+    expect( skcms_Parse(ptr, len, &p) && p.has_trc && !skcms_IsSRGB(&p.trc[0].parametric) );
     free(ptr);
 }
 
@@ -915,7 +915,9 @@
     expect( skcms_Parse(ptr, len, &sRGB) );
 
     skcms_ICCProfile linear_sRGB = sRGB;
-    linear_sRGB.tf = (skcms_TransferFunction){ 1,1,0,0,0,0,0 };
+    linear_sRGB.trc[0].parametric = (skcms_TransferFunction){ 1,1,0,0,0,0,0 };
+    linear_sRGB.trc[1].parametric = (skcms_TransferFunction){ 1,1,0,0,0,0,0 };
+    linear_sRGB.trc[2].parametric = (skcms_TransferFunction){ 1,1,0,0,0,0,0 };
 
     // Enough to hit all distinct bytes when interpreted as RGB 888.
     uint8_t src[258],
@@ -929,7 +931,7 @@
                             258/3) );
 
     for (int i = 0; i < 256; i++) {
-        float linear = skcms_TransferFunction_eval(&sRGB.tf, i * (1/255.0f));
+        float linear = skcms_TransferFunction_eval(&sRGB.trc[0].parametric, i * (1/255.0f));
         uint8_t expected = (uint8_t)(linear * 255.0f + 0.5f);
 
         // There is one known failure today: