Revert "use linear segment instead of recalculating it"

This reverts commit 86807d30cc2951021e81dc4507a5c14b37aebd31.

Reason for revert: <INSERT REASONING HERE>

Original change's description:
> use linear segment instead of recalculating it
> 
> Change-Id: I55f8e5d23f7f77681f45cfe2255ef8dda416497f
> Reviewed-on: https://skia-review.googlesource.com/123583
> Reviewed-by: Brian Osman <brianosman@google.com>
> Commit-Queue: Brian Osman <brianosman@google.com>
> Commit-Queue: Mike Klein <mtklein@google.com>
> Auto-Submit: Mike Klein <mtklein@chromium.org>

TBR=mtklein@chromium.org,mtklein@google.com,brianosman@google.com

Change-Id: Ia4703dcaea1b58a9791e7907078a8c6af588539a
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://skia-review.googlesource.com/123680
Reviewed-by: Mike Klein <mtklein@google.com>
Commit-Queue: Mike Klein <mtklein@google.com>
diff --git a/profiles/misc/MartiMaria_browsertest_HARD.icc.txt b/profiles/misc/MartiMaria_browsertest_HARD.icc.txt
index 38fdd04..46b4cf2 100644
--- a/profiles/misc/MartiMaria_browsertest_HARD.icc.txt
+++ b/profiles/misc/MartiMaria_browsertest_HARD.icc.txt
@@ -49,4 +49,4 @@
 	7b8069 7b8069 7b8069 7b8069 7b8069 7b8069 7b8069
 	7b8069 7b8069 7b8069 7b8069 7b8069 060605 7b8069
 	7b8069 7b8069 7b8069 7b8069 686c59 7b8069 7b8069
-polyTF[1] = 0 0 0.003876 inf
+polyTF[1] = 0 0 0.003876 1
diff --git a/profiles/misc/sRGB_lcms.icc.txt b/profiles/misc/sRGB_lcms.icc.txt
index 591b2f0..7030fb2 100644
--- a/profiles/misc/sRGB_lcms.icc.txt
+++ b/profiles/misc/sRGB_lcms.icc.txt
@@ -38,6 +38,6 @@
 	2a4215 322481 110a31 582e06 599714 03020c 4f59a4
 	63a91b 43292c 394539 5c3b22 548d3f 4d3018 506084
 This profile ≈ sRGB.
-polyTF[0] = 0.2938 0.7042 0.07739 0.04045
-polyTF[1] = 0.2938 0.7042 0.07739 0.04045
-polyTF[2] = 0.2938 0.7042 0.07739 0.04045
+polyTF[0] = 0.2941 0.7039 0.07759 0.04314
+polyTF[1] = 0.2941 0.7039 0.07759 0.04314
+polyTF[2] = 0.2941 0.7039 0.07759 0.04314
diff --git a/profiles/mobile/Display_P3_parametric.icc.txt b/profiles/mobile/Display_P3_parametric.icc.txt
index 8916828..865645a 100644
--- a/profiles/mobile/Display_P3_parametric.icc.txt
+++ b/profiles/mobile/Display_P3_parametric.icc.txt
@@ -37,6 +37,6 @@
 	6c616e 5f3a66 2e5e07 5e2b62 371928 293053 5a6591
 	234012 34258c 120a35 673203 499209 03020d 4b58ad
 	4fa40f 4d2b2d 364439 683e21 448939 573317 4b5e8a
-polyTF[0] = 0.2938 0.7042 0.07739 0.04045
-polyTF[1] = 0.2938 0.7042 0.07739 0.04045
-polyTF[2] = 0.2938 0.7042 0.07739 0.04045
+polyTF[0] = 0.2941 0.7039 0.07759 0.04314
+polyTF[1] = 0.2941 0.7039 0.07759 0.04314
+polyTF[2] = 0.2941 0.7039 0.07759 0.04314
diff --git a/profiles/mobile/iPhone7p.icc.txt b/profiles/mobile/iPhone7p.icc.txt
index bb59c5e..80366bc 100644
--- a/profiles/mobile/iPhone7p.icc.txt
+++ b/profiles/mobile/iPhone7p.icc.txt
@@ -36,6 +36,6 @@
 	6c616e 5f3a65 2d5e07 5e2b62 371928 293053 5a6591
 	234012 34258c 120a35 673203 499209 03020d 4b58ad
 	4fa40f 4d2b2d 364439 683e21 448939 573317 4b5e8a
-polyTF[0] = 0.2941 0.704 0.077 0.039
-polyTF[1] = 0.2941 0.704 0.077 0.039
-polyTF[2] = 0.2941 0.704 0.077 0.039
+polyTF[0] = 0.2945 0.7035 0.07733 0.04314
+polyTF[1] = 0.2945 0.7035 0.07733 0.04314
+polyTF[2] = 0.2945 0.7035 0.07733 0.04314
diff --git a/profiles/mobile/sRGB_parametric.icc.txt b/profiles/mobile/sRGB_parametric.icc.txt
index 05bed41..04c70cc 100644
--- a/profiles/mobile/sRGB_parametric.icc.txt
+++ b/profiles/mobile/sRGB_parametric.icc.txt
@@ -38,6 +38,6 @@
 	2a4215 322481 110a31 582e06 599714 03020c 4f59a4
 	63a91b 43292c 394539 5c3b22 548d3f 4d3018 506084
 This profile ≈ sRGB.
-polyTF[0] = 0.2938 0.7042 0.07739 0.04045
-polyTF[1] = 0.2938 0.7042 0.07739 0.04045
-polyTF[2] = 0.2938 0.7042 0.07739 0.04045
+polyTF[0] = 0.2941 0.7039 0.07759 0.04314
+polyTF[1] = 0.2941 0.7039 0.07759 0.04314
+polyTF[2] = 0.2941 0.7039 0.07759 0.04314
diff --git a/src/PolyTF.c b/src/PolyTF.c
index 4b31b18..451a427 100644
--- a/src/PolyTF.c
+++ b/src/PolyTF.c
@@ -66,7 +66,7 @@
     }
 
     const int N = curve->table_entries == 0 ? 256
-                                            : (int)curve->table_entries;
+                                            :(int)curve->table_entries;
 
     // We'll test the quality of our fit by roundtripping through a skcms_TransferFunction,
     // either the inverse of the curve itself if it is parametric, or of its approximation if not.
@@ -77,74 +77,64 @@
     } else if (!skcms_ApproximateCurve(curve, &baseline, &err)) {
         return false;
     }
-
-    // We'll borrow the linear section from baseline, which is either
-    // exactly correct, or already the approximation we'd use anyway.
-    tf->C = baseline.c;
-    tf->D = baseline.d;
-    if (baseline.f != 0) {
-        return false;  // Can't fit this (rare) kind of curve here.
-    }
-
-    // Detect linear baseline: (ax + b)^g + e --> ax ~~> Cx
-    if (baseline.g == 1 && baseline.d == 0 && baseline.b + baseline.e == 0) {
-        tf->A = 0;
-        tf->B = 0;
-        tf->C = baseline.a;
-        tf->D = INFINITY_;   // Always use Cx, never Ax^3+Bx^2+(1-A-B)
-        return true;
-    }
-    // This case is less likely, but also guards against divide by zero below.
-    if (tf->D == 1) {
-        tf->A = 0;
-        tf->B = 0;
-        return true;
-    }
-
-    // Number of points already fit in the linear section.
-    // If the curve isn't parametric and we approximated instead, this should be exact.
-    const int L = (int)(tf->D * (N-1)) + 1;
-
-    // TODO: handle special case of L == N-1 to avoid /0 in Gauss-Newton.
-
     skcms_TransferFunction inv;
     if (!skcms_TransferFunction_invert(&baseline, &inv)) {
         return false;
     }
 
-    // Start with guess A = 0, i.e. f(x) ≈ x^2.
-    float P[4] = {0, 0,0,0};
-    for (int i = 0; i < 3; i++) {
-        if (!skcms_gauss_newton_step(skcms_eval_curve, curve,
-                                     eval_poly_tf, tf,
-                                     grad_poly_tf, tf,
-                                     P,
-                                     tf->D, 1, N-L)) {
+    const float kTolerances[] = { 1.5f / 65535.0f, 1.0f / 512.0f };
+    for (int t = 0; t < ARRAY_COUNT(kTolerances); t++) {
+        float f;
+        const int L = skcms_fit_linear(curve, N, kTolerances[t], &tf->C, &tf->D, &f);
+        if (f != 0) {
             return false;
         }
+
+        if (tf->D == 1) {
+            tf->A = 0;
+            tf->B = 0;
+            return true;
+        }
+
+        // Start with guess A = 0, i.e. f(x) = x^2, gamma = 2.
+        float P[4] = {0, 0,0,0};
+
+        for (int i = 0; i < 3; i++) {
+            if (!skcms_gauss_newton_step(skcms_eval_curve, curve,
+                                         eval_poly_tf, tf,
+                                         grad_poly_tf, tf,
+                                         P,
+                                         tf->D, 1, N-L)) {
+                goto NEXT;
+            }
+        }
+
+        float A = tf->A = P[0],
+              C = tf->C,
+              D = tf->D;
+        tf->B = (C*D - A*(D*D*D - 1) - 1) / (D*D - 1);
+
+        for (int i = 0; i < N; i++) {
+            float x = i * (1.0f/(N-1));
+
+            float rt = skcms_TransferFunction_eval(&inv, eval_poly_tf(x, tf, P));
+            if (!isfinitef_(rt)) {
+                goto NEXT;
+            }
+
+            const int tol = (i == 0 || i == N-1) ? 0
+                                                 : N/256;
+            int ix = (int)((N-1) * rt + 0.5f);
+            if (abs(i - ix) > tol) {
+                goto NEXT;
+            }
+        }
+        return true;
+
+    NEXT: ;
     }
 
-    float A = tf->A = P[0],
-          C = tf->C,
-          D = tf->D;
-    tf->B = (C*D - A*(D*D*D - 1) - 1) / (D*D - 1);
-
-    for (int i = 0; i < N; i++) {
-        float x = i * (1.0f/(N-1));
-
-        float rt = skcms_TransferFunction_eval(&inv, eval_poly_tf(x, tf, P));
-        if (!isfinitef_(rt)) {
-            return false;
-        }
-
-        const int tol = (i == 0 || i == N-1) ? 0
-                                             : N/256;
-        int ix = (int)((N-1) * rt + 0.5f);
-        if (abs(i - ix) > tol) {
-            return false;
-        }
-    }
-    return true;
+    return false;
 }
 
 void skcms_OptimizeForSpeed(skcms_ICCProfile* profile) {