Fix Sk4fLinearGradient initial interval pinning

For repeat/mirror mode, fx tiling needs to ensure the value doesn't
collapse to the open interval value due to float arithmetic.

Clamp to the next lower representable value.

BUG=skia:5955
R=reed@google.com

GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=4784

Change-Id: I635394d15a80276e88c18a499f93f3047464f190
Reviewed-on: https://skia-review.googlesource.com/4784
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Florin Malita <fmalita@chromium.org>
diff --git a/src/effects/gradients/Sk4fLinearGradient.cpp b/src/effects/gradients/Sk4fLinearGradient.cpp
index 29d9088..45083f7 100644
--- a/src/effects/gradients/Sk4fLinearGradient.cpp
+++ b/src/effects/gradients/Sk4fLinearGradient.cpp
@@ -92,14 +92,24 @@
 
 template<>
 SkScalar pinFx<SkShader::kRepeat_TileMode>(SkScalar fx) {
-    const SkScalar f = SkScalarFraction(fx);
-    return f < 0 ? f + 1 : f;
+    SkScalar f = SkScalarFraction(fx);
+    if (f < 0) {
+        f = SkTMin(f + 1, nextafterf(1, 0));
+    }
+    SkASSERT(f >= 0);
+    SkASSERT(f < 1.0f);
+    return f;
 }
 
 template<>
 SkScalar pinFx<SkShader::kMirror_TileMode>(SkScalar fx) {
-    const SkScalar f = SkScalarMod(fx, 2.0f);
-    return f < 0 ? f + 2 : f;
+    SkScalar f = SkScalarMod(fx, 2.0f);
+    if (f < 0) {
+        f = SkTMin(f + 2, nextafterf(2, 0));
+    }
+    SkASSERT(f >= 0);
+    SkASSERT(f < 2.0f);
+    return f;
 }
 
 // true when x is in [k1,k2), or [k2, k1) when the interval is reversed.