ccpr: Clip quadratic hulls more efficiently

To minimize area, we should clip by the tangent line at maximum
height. Not mid-tangent. This is also easier to find.

Bug: skia:
Change-Id: I5099b62537f72e51e29bbced7998c0e588e287d9
Reviewed-on: https://skia-review.googlesource.com/119740
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Jim Van Verth <jvanverth@google.com>
diff --git a/src/gpu/ccpr/GrCCCoverageProcessor.h b/src/gpu/ccpr/GrCCCoverageProcessor.h
index 40339ba..6818027 100644
--- a/src/gpu/ccpr/GrCCCoverageProcessor.h
+++ b/src/gpu/ccpr/GrCCCoverageProcessor.h
@@ -113,10 +113,13 @@
         // Called before generating geometry. Subclasses may set up internal member variables during
         // this time that will be needed during onEmitVaryings (e.g. transformation matrices).
         //
-        // If the optional 'tighterHull' parameter is not null and gets filled out by the subclass,
-        // the the Impl will generate geometry around those points rather than the input points.
+        // If the 'outHull4' parameter is provided, and there are not 4 input points, the subclass
+        // is required to fill it with the name of a 4-point hull around which the Impl can generate
+        // its geometry. If it is left unchanged, the Impl will use the regular input points.
         virtual void emitSetupCode(GrGLSLVertexGeoBuilder*, const char* pts, const char* wind,
-                                   const char** tighterHull = nullptr) const {}
+                                   const char** outHull4 = nullptr) const {
+            SkASSERT(!outHull4);
+        }
 
         void emitVaryings(GrGLSLVaryingHandler* varyingHandler, GrGLSLVarying::Scope scope,
                           SkString* code, const char* position, const char* coverage,
diff --git a/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp b/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp
index 561a293..a1f180b 100644
--- a/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp
+++ b/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp
@@ -285,7 +285,7 @@
     v->defineConstant("bloat", bloat);
 
     const char* hullPts = "pts";
-    fShader->emitSetupCode(v, "pts", "wind", &hullPts);
+    fShader->emitSetupCode(v, "pts", "wind", (4 == fNumSides) ? &hullPts : nullptr);
 
     // Reverse all indices if the wind is counter-clockwise: [0, 1, 2] -> [2, 1, 0].
     v->codeAppendf("int clockwise_indices = wind > 0 ? %s : 0x%x - %s;",
diff --git a/src/gpu/ccpr/GrCCCubicShader.cpp b/src/gpu/ccpr/GrCCCubicShader.cpp
index 4c9485e..f8a8352 100644
--- a/src/gpu/ccpr/GrCCCubicShader.cpp
+++ b/src/gpu/ccpr/GrCCCubicShader.cpp
@@ -14,7 +14,7 @@
 using Shader = GrCCCoverageProcessor::Shader;
 
 void GrCCCubicShader::emitSetupCode(GrGLSLVertexGeoBuilder* s, const char* pts,
-                                    const char* wind, const char** /*tighterHull*/) const {
+                                    const char* wind, const char** /*outHull4*/) const {
     // Define a function that normalizes the homogeneous coordinates T=t/s in order to avoid
     // exponent overflow.
     SkString normalizeHomogCoordFn;
diff --git a/src/gpu/ccpr/GrCCCubicShader.h b/src/gpu/ccpr/GrCCCubicShader.h
index 2455880..d6c5e26 100644
--- a/src/gpu/ccpr/GrCCCubicShader.h
+++ b/src/gpu/ccpr/GrCCCubicShader.h
@@ -24,7 +24,7 @@
 class GrCCCubicShader : public GrCCCoverageProcessor::Shader {
 public:
     void emitSetupCode(GrGLSLVertexGeoBuilder*, const char* pts, const char* wind,
-                       const char** tighterHull) const override;
+                       const char** outHull4) const override;
 
     void onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code,
                         const char* position, const char* coverage,
diff --git a/src/gpu/ccpr/GrCCQuadraticShader.cpp b/src/gpu/ccpr/GrCCQuadraticShader.cpp
index 2398282..00e16ce 100644
--- a/src/gpu/ccpr/GrCCQuadraticShader.cpp
+++ b/src/gpu/ccpr/GrCCQuadraticShader.cpp
@@ -7,14 +7,11 @@
 
 #include "GrCCQuadraticShader.h"
 
-#include "glsl/GrGLSLVertexGeoBuilder.h"
 #include "glsl/GrGLSLFragmentShaderBuilder.h"
 #include "glsl/GrGLSLVertexGeoBuilder.h"
 
-using Shader = GrCCCoverageProcessor::Shader;
-
 void GrCCQuadraticShader::emitSetupCode(GrGLSLVertexGeoBuilder* s, const char* pts,
-                                        const char* wind, const char** tighterHull) const {
+                                        const char* wind, const char** outHull4) const {
     s->declareGlobal(fQCoordMatrix);
     s->codeAppendf("%s = float2x2(1, 1, .5, 0) * inverse(float2x2(%s[2] - %s[0], %s[1] - %s[0]));",
                    fQCoordMatrix.c_str(), pts, pts, pts, pts);
@@ -27,21 +24,16 @@
     s->codeAppendf("float2 edgept1 = %s[%s > 0 ? 0 : 2];", pts, wind);
     Shader::EmitEdgeDistanceEquation(s, "edgept0", "edgept1", fEdgeDistanceEquation.c_str());
 
-    if (tighterHull) {
-        // Find the T value whose tangent is halfway between the tangents at the endpionts.
-        s->codeAppendf("float2 tan0 = %s[1] - %s[0];", pts, pts);
-        s->codeAppendf("float2 tan1 = %s[2] - %s[1];", pts, pts);
-        s->codeAppend ("float2 midnorm = normalize(tan0) - normalize(tan1);");
-        s->codeAppend ("float2 T = midnorm * float2x2(tan0 - tan1, tan0);");
-        s->codeAppend ("float t = clamp(T.t / T.s, 0, 1);"); // T.s!=0; we cull flat curves on CPU.
-
-        // Clip the bezier triangle by the tangent at our new t value. This is a simple application
-        // for De Casteljau's algorithm.
-        s->codeAppendf("float4x2 quadratic_hull = float4x2(%s[0], "
-                                                          "%s[0] + tan0 * t, "
-                                                          "%s[1] + tan1 * t, "
-                                                          "%s[2]);", pts, pts, pts, pts);
-        *tighterHull = "quadratic_hull";
+    if (outHull4) {
+        // Clip the bezier triangle by the tangent line at maximum height. Quadratics have the nice
+        // property that maximum height always occurs at T=.5. This is a simple application for
+        // De Casteljau's algorithm.
+        s->codeAppendf("float2 quadratic_hull[4] = float2[4](%s[0], "
+                                                            "(%s[0] + %s[1]) * .5, "
+                                                            "(%s[1] + %s[2]) * .5, "
+                                                            "%s[2]);",
+                                                            pts, pts, pts, pts, pts, pts);
+        *outHull4 = "quadratic_hull";
     }
 }
 
diff --git a/src/gpu/ccpr/GrCCQuadraticShader.h b/src/gpu/ccpr/GrCCQuadraticShader.h
index daf9eee..bf29b64 100644
--- a/src/gpu/ccpr/GrCCQuadraticShader.h
+++ b/src/gpu/ccpr/GrCCQuadraticShader.h
@@ -23,7 +23,7 @@
 class GrCCQuadraticShader : public GrCCCoverageProcessor::Shader {
 public:
     void emitSetupCode(GrGLSLVertexGeoBuilder*, const char* pts, const char* wind,
-                       const char** tighterHull) const override;
+                       const char** outHull4) const override;
 
     void onEmitVaryings(GrGLSLVaryingHandler*, GrGLSLVarying::Scope, SkString* code,
                         const char* position, const char* coverage,