reject negative inv.a

Turns out we _can_ create a (only very very slightly) negative a term
when inverting a profile that passes our sanity tests.

Reject them like we do in fitting.  Was thinking about nudging it up to
0, but that would imply some strange things, like x not mattering...

Bug: oss-fuzz:16581
Change-Id: I2b30a36250936042da08e0f1771f5dc7610b9853
Reviewed-on: https://skia-review.googlesource.com/c/skcms/+/236082
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Mike Klein <mtklein@google.com>
diff --git a/profiles/fuzz/negative_a_when_inverted.icc b/profiles/fuzz/negative_a_when_inverted.icc
new file mode 100644
index 0000000..e5e34d5
--- /dev/null
+++ b/profiles/fuzz/negative_a_when_inverted.icc
Binary files differ
diff --git a/profiles/fuzz/negative_a_when_inverted.icc.txt b/profiles/fuzz/negative_a_when_inverted.icc.txt
new file mode 100644
index 0000000..8c157bb
--- /dev/null
+++ b/profiles/fuzz/negative_a_when_inverted.icc.txt
@@ -0,0 +1,38 @@
+                Size : 0x00000090 : 144
+    Data color space : 0x47524159 : 'GRAY'
+                 PCS : 0x58595A20 : 'XYZ '
+           Tag count : 0x00000001 : 1
+
+ Tag    : Type   : Size   : Offset
+ ------ : ------ : ------ : --------
+ 'kTRC' : 'curv' :    102 : 32
+
+rTRC : 16-bit table with 41 entries
+gTRC : 16-bit table with 41 entries
+bTRC : 16-bit table with 41 entries
+ XYZ : | 0.95751953 0 0 |
+       | 0 1.0004883 0 |
+       | 0 0 0.82029724 |
+252 random bytes transformed to linear XYZD50 bytes:
+	4d201a 1f571a 1f201a 00201a 002074 1f201a 2d2000
+	1f201a 330d8d 1f001a 4d201a 1f2063 1f201a 1f201a
+	1f201a 1f201a 1f202c 1fb0ad 1f311a 679f1a 82201a
+	6e20a1 683e1a 1f203a 1f201a 1f2000 9c4f1a 1f201a
+	1f201a 1f001a b822bb 1f209f 1f3c1a b7201a 1f202f
+	1f201a 4d7cc4 1f5a1a 5a201a 1f201a 1f201a 1f201e
+	1f201a 1f885a 1f201a 1f201b 1a201a 1f136e 1f201a
+	a320ca 9c20a2 1f176c 1f201a 1f201a 1f204f 1f8f1a
+	002000 1f201a 1f201a 1f621a 1f201a 1f2087 1f5636
+	1f201a 1f001a 1f2034 1f461a 55251a 372057 1f201a
+	1f2006 000a1a 1f201a 1f201a 00202b 287c0e 77d31a
+	c1351a 1f201a 9d201a 1f3059 1f201a 1f0300 00201a
+81 edge-case pixels transformed to sRGB 8888 (unpremul):
+	00636462 00636462 00636462  00636462 00636462 00636462  00636462 00636462 00636462
+	00636462 00636462 00636462  00636462 00636462 00636462  00636462 00636462 00636462
+	00636462 00636462 00636462  00636462 00636462 00636462  00636462 00636462 00636462
+	7f636462 7f636462 7f636462  7f636462 7f636462 7f636462  7f636462 7f636462 7f636462
+	7f636462 7f636462 7f636462  7f636462 7f636462 7f636462  7f636462 7f636462 7f636462
+	7f636462 7f636462 7f636462  7f636462 7f636462 7f636462  7f636462 7f636462 7f636462
+	ff636462 ff636462 ff636462  ff636462 ff636462 ff636462  ff636462 ff636462 ff636462
+	ff636462 ff636462 ff636462  ff636462 ff636462 ff636462  ff636462 ff636462 ff636462
+	ff636462 ff636462 ff636462  ff636462 ff636462 ff636462  ff636462 ff636462 ff636462
diff --git a/skcms.cc b/skcms.cc
index 65188ca..12c1229 100644
--- a/skcms.cc
+++ b/skcms.cc
@@ -1476,13 +1476,18 @@
 
     // 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);
+    // of the source function if we're here.
 
-    // On the other hand our ad+b could have gone slightly negative here.  Tweak inv.b if needed.
+    // Just like when fitting the curve, there's really no way to rescue a < 0.
+    if (inv.a < 0) {
+        return false;
+    }
+    // On the other hand we can rescue an ad+b that's gone slightly negative here.
     if (inv.a * inv.d + inv.b < 0) {
         inv.b = -inv.a * inv.d;
     }
+
+    assert (inv.a >= 0);
     assert (inv.a * inv.d + inv.b >= 0);
 
     // Now in principle we're done.
diff --git a/tests.c b/tests.c
index 3b849c2..57083a7 100644
--- a/tests.c
+++ b/tests.c
@@ -680,6 +680,9 @@
 
     // Reasonable table, but gets approximated very badly
     "profiles/misc/crbug_976551.icc",                 // chromium:976551
+
+    // The a term goes negative when inverting.
+    "profiles/fuzz/negative_a_when_inverted.icc",     // oss-fuzz:16581
 };
 
 static void test_Parse(bool regen) {