Add missing b-tweak to skcms_TF_Invert()

First I added an assert (x >= 0) to powf_().

That failing helped me notice we're not
checking ad+b >=0 in tf_is_valid().

That failing helped me notice skcms_TF_Invert() can
take ad+b >= 0 inputs and create ad + b < 0 outputs.

To fix that, apply the same tweak to b we do when fitting.

To follow the story in smaller steps,
  1) https://skia-review.googlesource.com/c/skcms/+/235899
  2) https://skia-review.googlesource.com/c/skcms/+/235909
  3) https://skia-review.googlesource.com/c/skcms/+/235912

Bug: chromium:976551
Change-Id: If281a2151f41b6dd5bcc86992d2104576f7c985f
Reviewed-on: https://skia-review.googlesource.com/c/skcms/+/235913
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Mike Klein <mtklein@google.com>
diff --git a/profiles/fuzz/polytf_big_float_to_int_cast.icc.txt b/profiles/fuzz/polytf_big_float_to_int_cast.icc.txt
index ceb639a..979baac 100644
--- a/profiles/fuzz/polytf_big_float_to_int_cast.icc.txt
+++ b/profiles/fuzz/polytf_big_float_to_int_cast.icc.txt
@@ -1,48 +1 @@
-                Size : 0x0000020C : 524
-    Data color space : 0x20202020 : '    '
-                 PCS : 0x58595A20 : 'XYZ '
-           Tag count : 0x0000000A : 10
-
- Tag    : Type   : Size   : Offset
- ------ : ------ : ------ : --------
- '    ' : '    ' :     32 : 32
- '    ' : '    ' :     32 : 288
- '    ' : '    ' :     32 : 288
- '    ' : '    ' :     32 : 288
- 'rXYZ' : 'XYZ ' :     32 : 400
- 'gXYZ' : 'XYZ ' :     32 : 420
- 'bXYZ' : 'XYZ ' :     32 : 440
- 'rTRC' : 'para' :     32 : 456
- 'gTRC' : 'para' :     32 : 456
- 'bTRC' : 'curv' :     32 : 460
-
-rTRC : 1.525879e-05, 0.003890991, -32768, 8224.125, 0, 0, 0
-gTRC : 1.525879e-05, 0.003890991, -32768, 8224.125, 0, 0, 0
-bTRC : 0, 1, 0, 0, 0, 0, 0
- XYZ : | 8224.125 8224.125 8224.125 |
-       | 8224.125 8224.125 8224.125 |
-       | 8224.125 -223.87451 28769.447 |
- !!! This does not appear to use a D50 whitepoint, rather [24672.4 24672.4 36769.7]
-252 random bytes transformed to linear XYZD50 bytes:
-	ffffff ffffff ffffff ffffff ffffff ffffff ffffff
-	ffffff ffffff ffffff ffffff ffffff ffffff ffffff
-	ffffff ffffff ffffff ffffff ffffff ffffff ffffff
-	ffffff ffffff ffffff ffffff ffffff ffffff ffffff
-	ffffff ffffff ffffff ffffff ffffff ffffff ffffff
-	ffffff ffffff ffffff ffffff ffffff ffffff ffffff
-	ffffff ffffff ffffff ffffff ffffff ffffff ffffff
-	ffffff ffffff ffffff ffffff ffffff ffffff ffffff
-	ffffff ffffff ffffff ffffff ffffff ffffff ffffff
-	ffffff ffffff ffffff ffffff ffffff ffffff ffffff
-	ffffff ffffff ffffff ffffff ffffff ffffff ffffff
-	ffffff ffffff ffffff ffffff ffffff ffffff ffffff
-81 edge-case pixels transformed to sRGB 8888 (unpremul):
-	00ffffff 00ffffff 00ffffff  00ffffff 00ffffff 00ffffff  00ffffff 00ffffff 00ffffff
-	00ffffff 00ffffff 00ffffff  00ffffff 00ffffff 00ffffff  00ffffff 00ffffff 00ffffff
-	00ffffff 00ffffff 00ffffff  00ffffff 00ffffff 00ffffff  00ffffff 00ffffff 00ffffff
-	7fffffff 7fffffff 7fffffff  7fffffff 7fffffff 7fffffff  7fffffff 7fffffff 7fffffff
-	7fffffff 7fffffff 7fffffff  7fffffff 7fffffff 7fffffff  7fffffff 7fffffff 7fffffff
-	7fffffff 7fffffff 7fffffff  7fffffff 7fffffff 7fffffff  7fffffff 7fffffff 7fffffff
-	ffffffff ffffffff ffffffff  ffffffff ffffffff ffffffff  ffffffff ffffffff ffffffff
-	ffffffff ffffffff ffffffff  ffffffff ffffffff ffffffff  ffffffff ffffffff ffffffff
-	ffffffff ffffffff ffffffff  ffffffff ffffffff ffffffff  ffffffff ffffffff ffffffff
+Unable to parse ICC profile
diff --git a/profiles/misc/Coated_FOGRA39_CMYK.icc.txt b/profiles/misc/Coated_FOGRA39_CMYK.icc.txt
index 4a0e2fe..cae8402 100644
--- a/profiles/misc/Coated_FOGRA39_CMYK.icc.txt
+++ b/profiles/misc/Coated_FOGRA39_CMYK.icc.txt
@@ -23,7 +23,7 @@
  A2B : "A", CLUT, "B"
  "A" : 4 inputs
   A0 : 16-bit table with 256 entries
-  ~= : 1.05448, 1.018715, -0.007989922, 0.8365758, 0.007843138, 0.0066185, 0 (Max error: 0.890015) (D-gap: 5.71203e-05)
+  ~= : 1.05448, 1.018715, -0.007989922, 0.8365758, 0.007843138, 0.0066185, 0 (Max error: 0.0167046) (D-gap: 5.71203e-05)
   A1 : 16-bit table with 256 entries
   ~= : 1.117216, 1.017609, 0.0126555, 0.7665369, 0.007843138, -0.007049561, 0 (Max error: 0.0234528) (D-gap: 3.23332e-05)
   A2 : 16-bit table with 256 entries
diff --git a/profiles/misc/DisplayCal_ASUS_NonMonotonic.icc.txt b/profiles/misc/DisplayCal_ASUS_NonMonotonic.icc.txt
index 0556959..5bbce8a 100644
--- a/profiles/misc/DisplayCal_ASUS_NonMonotonic.icc.txt
+++ b/profiles/misc/DisplayCal_ASUS_NonMonotonic.icc.txt
@@ -31,7 +31,7 @@
  'meta' : 'dict' :   2312 : 738448
 
 rTRC : 16-bit table with 256 entries
-  ~= : 1.929522, 1.131104, -0.133071, 0.03579767, 0.1176471, 0.004390717, 0 (Max error: 1.34651e+35) (D-gap: 0.000179225)
+  ~= : 1.929522, 1.131104, -0.133071, 0.03579767, 0.1176471, 0.004390717, 0 (Max error: 0.0831201) (D-gap: 0.000179225)
 gTRC : 16-bit table with 256 entries
   ~= : 2.287451, 0.9762917, 0.03631328, 0.03112842, 0.1921569, -0.02641296, 0 (Max error: 0.0558824) (D-gap: 0.000206613)
 bTRC : 16-bit table with 256 entries
diff --git a/profiles/misc/Japan_Color_2001_Coated.icc.txt b/profiles/misc/Japan_Color_2001_Coated.icc.txt
index a8f9508..df4905b 100644
--- a/profiles/misc/Japan_Color_2001_Coated.icc.txt
+++ b/profiles/misc/Japan_Color_2001_Coated.icc.txt
@@ -19,9 +19,9 @@
  A2B : "A", CLUT, "B"
  "A" : 4 inputs
   A0 : 16-bit table with 256 entries
-  ~= : 1.010957, 1.063629, -0.03336876, 0.7801556, 0.03137255, 0.02462769, 0 (Max error: 0.0513268) (D-gap: 0.000152213)
+  ~= : 1.010957, 1.063629, -0.03336876, 0.7801556, 0.03137255, 0.02462769, 0 (Max error: 0.0513306) (D-gap: 0.000152213)
   A1 : 16-bit table with 256 entries
-  ~= : 1.127547, 1.01329, -0.000483401, 0.3501945, 0.003921568, -0.000289917, 0 (Max error: 0.0123787) (D-gap: 3.26649e-05)
+  ~= : 1.117948, 1.022087, -0.0280573, 0.6270149, 0.02745098, 0.01732635, 0 (Max error: 0.00934219) (D-gap: 0.000114178)
   A2 : 16-bit table with 256 entries
   ~= : 1.158917, 0.990242, 0.04165715, 0.6193256, 0.02352941, -0.02733612, 0 (Max error: 0.00832367) (D-gap: 0.000154509)
   A3 : 16-bit table with 256 entries
diff --git a/profiles/misc/Phase_One_P25.icc.txt b/profiles/misc/Phase_One_P25.icc.txt
index 7f6fd47..cbf18f2 100644
--- a/profiles/misc/Phase_One_P25.icc.txt
+++ b/profiles/misc/Phase_One_P25.icc.txt
@@ -22,7 +22,7 @@
   ~= : 0.3802269, 1.743515, 0.01529081, 3.844358, 0.007843138, -0.2299347, 0 (Max error: 0.0201225) (D-gap: 9.07481e-06)
 gTRC : 16-bit table with 256 entries
 bTRC : 16-bit table with 256 entries
-  ~= : 0.7390234, 0.8481178, -0.009977858, 2.721141, 0.01176471, 0.03213882, 0 (Max error: 0.139809) (D-gap: 0.000125397)
+  ~= : 0.7390234, 0.8481178, -0.009977858, 2.721141, 0.01176471, 0.03213882, 0 (Max error: 0.139824) (D-gap: 0.000125397)
  XYZ : | 0.64790344 0.35736084 0.15641785 |
        | 0.3829193 1.109726 0 |
        | 0.08326721 0.6792755 0.52342224 |
diff --git a/profiles/misc/US_Web_Coated_SWOP_CMYK.icc.txt b/profiles/misc/US_Web_Coated_SWOP_CMYK.icc.txt
index bcd76ba..35f97bf 100644
--- a/profiles/misc/US_Web_Coated_SWOP_CMYK.icc.txt
+++ b/profiles/misc/US_Web_Coated_SWOP_CMYK.icc.txt
@@ -21,9 +21,9 @@
   A0 : 16-bit table with 256 entries
   ~= : 0.7457523, 1.273102, 0.2824915, 2.132296, 0.003921569, -0.3862457, 0 (Max error: 0.00514561) (D-gap: 5.51855e-05)
   A1 : 16-bit table with 256 entries
-  ~= : 1.001741, 0.9817963, -0.01540073, 1.622568, 0.01568628, 0.02549744, 0 (Max error: 0.00973922) (D-gap: 4.53889e-05)
+  ~= : 1.001741, 0.9817963, -0.01540073, 1.622568, 0.01568628, 0.02549744, 0 (Max error: 0.00973541) (D-gap: 4.53889e-05)
   A2 : 16-bit table with 256 entries
-  ~= : 1.041717, 0.9965515, -0.003908046, 2.011673, 0.003921569, 0.007892609, 0 (Max error: 0.022772) (D-gap: 3.69456e-06)
+  ~= : 1.043713, 0.9970474, -0.01563996, 1.68677, 0.01568628, 0.02657318, 0 (Max error: 0.0163442) (D-gap: 0.000114037)
   A3 : 16-bit table with 256 entries
 CLUT : 9 x 9 x 9 x 9 (16 bpp)
  "B" : 3 outputs
diff --git a/profiles/misc/crbug_976551.icc.txt b/profiles/misc/crbug_976551.icc.txt
index d36933d..e614b09 100644
--- a/profiles/misc/crbug_976551.icc.txt
+++ b/profiles/misc/crbug_976551.icc.txt
@@ -21,13 +21,13 @@
  'mmod' : 'mmod' :     40 : 13080
 
 rTRC : 16-bit table with 1024 entries
-  ~= : 1.348469, 1.17157, -0.009161836, 0.009756237, 0.007820137, 0.0001716614, 0 (Max error: 7.31654e+16) (D-gap: 9.53663e-05)
+  ~= : 1.408492, 1.078773, -0.08119801, 0.1001471, 0.07526882, 0.007678986, 0 (Max error: 0.0193188) (D-gap: 0.000141029)
 gTRC : 16-bit table with 1024 entries
-  ~= : 1.378535, 1.13559, -0.007770408, 0.008919988, 0.00684262, 0.0001716614, 0 (Max error: 1.72219e+18) (D-gap: 0.000110625)
+  ~= : 1.430862, 1.067261, -0.07720166, 0.1031524, 0.07233626, 0.007591248, 0 (Max error: 0.0184169) (D-gap: 0.000129586)
 bTRC : 16-bit table with 1024 entries
-  ~= : 1.326482, 1.226715, -0.00959308, 0.009756237, 0.007820137, 0.0001296997, 0 (Max error: 4.54796e+15) (D-gap: 5.34046e-05)
-Best : 1.326482, 1.226715, -0.00959308, 0.009756237, 0.007820137, 0.0001296997, 0 (D-gap: 5.34046e-05)
-Inv  : 0.7538736, 0.7626305, -9.891295e-05, 102.4985, 7.629511e-05, 0.007846832, -0 (D-gap: -4.54796e+15)
+  ~= : 1.335367, 1.135376, -0.0876781, 0.09840215, 0.07722384, 0.007732391, 0 (Max error: 0.0542429) (D-gap: 0.000133399)
+Best : 1.408492, 1.078773, -0.08119801, 0.1001471, 0.07526882, 0.007678986, 0 (D-gap: 0.000141029)
+Inv  : 0.7099792, 0.8987885, -0.006775029, 9.985308, 0.007537957, 0.0752182, -0 (D-gap: -5.06192e-05)
  XYZ : | 0.512558 0.29548645 0.15614319 |
        | 0.24029541 0.7005768 0.059127808 |
        | -0.0010375977 0.042297363 0.7836609 |
diff --git a/skcms.cc b/skcms.cc
index a27d025..65188ca 100644
--- a/skcms.cc
+++ b/skcms.cc
@@ -266,6 +266,11 @@
         return false;
     }
 
+    // It's rather _complex_ to raise a negative number to a fractional power tf->g.
+    if (tf->a * tf->d + tf->b < 0) {
+        return false;
+    }
+
     return true;
 }
 
@@ -1404,6 +1409,7 @@
 }
 
 float powf_(float x, float y) {
+    assert (x >= 0);
     return (x == 0) || (x == 1) ? x
                                 : exp2f_(log2f_(x) * y);
 }
@@ -1468,6 +1474,17 @@
     inv.b = -k * src->e;
     inv.e = -src->b / src->a;
 
+    // We need to enforce the same constraints here that we do when fitting a curve,
+    // a >= 0 and ad+b >= 0.  These constraints are checked by tf_is_valid(), so they're true
+    // of the source function if we're here.  And if the source a >= 0, inv.a definitely is too.
+    assert (inv.a >= 0);
+
+    // On the other hand our ad+b could have gone slightly negative here.  Tweak inv.b if needed.
+    if (inv.a * inv.d + inv.b < 0) {
+        inv.b = -inv.a * inv.d;
+    }
+    assert (inv.a * inv.d + inv.b >= 0);
+
     // Now in principle we're done.
     // But to preserve the valuable invariant inv(src(1.0f)) == 1.0f,
     // we'll tweak e.  These two values should be close to each other,
@@ -1663,6 +1680,9 @@
         P[2] = -P[1] * tf->d;
     }
 
+    assert (P[1] >= 0 &&
+            P[1] * tf->d + P[2] >= 0);
+
     tf->g = P[0];
     tf->a = P[1];
     tf->b = P[2];