Prevent outset Ws from going negative

Bug: skia:9028
Change-Id: I8e3d37050d3fce7602eee62ae911eae756e603a2
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/211100
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/src/gpu/ops/GrQuadPerEdgeAA.cpp b/src/gpu/ops/GrQuadPerEdgeAA.cpp
index b9a7b45..e2714a6 100644
--- a/src/gpu/ops/GrQuadPerEdgeAA.cpp
+++ b/src/gpu/ops/GrQuadPerEdgeAA.cpp
@@ -258,6 +258,19 @@
                     V4f(0.f)) / denom;                            /* !B      */
     }
 
+    V4f newW = quad->fW + a * e1w + b * e2w;
+    // If newW < 0, scale a and b such that the point reaches the infinity plane instead of crossing
+    // This breaks orthogonality of inset/outsets, but GPUs don't handle negative Ws well so this
+    // is far less visually disturbing (likely not noticeable since it's at extreme perspective).
+    // The alternative correction (multiply xyw by -1) has the disadvantage of changing how local
+    // coordinates would be interpolated.
+    static const float kMinW = 1e-6f;
+    if (any(newW < 0.f)) {
+        V4f scale = if_then_else(newW < kMinW, (kMinW - quad->fW) / (newW - quad->fW), V4f(1.f));
+        a *= scale;
+        b *= scale;
+    }
+
     quad->fX += a * e1x + b * e2x;
     quad->fY += a * e1y + b * e2y;
     quad->fW += a * e1w + b * e2w;