Track quad type on GrQuad directly

This makes subsequent higher-level drawing APIs more compact, and
shouldn't come with a performance hit. Everywhere we used to need
a GrPerspQuad, we'd also take the GrQuadType as a second argument.
The quad list types already deconstruct the quad so there's no
extra overhead in the op's memory usage.

It also improves usability and decreases the likelihood that an
incorrect quad type is ever associated with the quad.

Bug: skia:
Change-Id: Iba908fb133ad664744a5788a7088d90de0d3a1c2
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/214820
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
diff --git a/src/gpu/GrQuad.cpp b/src/gpu/GrQuad.cpp
index 379d1f6..bd01a68 100644
--- a/src/gpu/GrQuad.cpp
+++ b/src/gpu/GrQuad.cpp
@@ -69,10 +69,39 @@
     *ys = V4f{skQuadPts[0].fY, skQuadPts[3].fY, skQuadPts[1].fY, skQuadPts[2].fY};
 }
 
+// If an SkRect is transformed by this matrix, what class of quad is required to represent it.
+static GrQuadType quad_type_for_transformed_rect(const SkMatrix& matrix) {
+    if (matrix.rectStaysRect()) {
+        return GrQuadType::kRect;
+    } else if (matrix.preservesRightAngles()) {
+        return GrQuadType::kRectilinear;
+    } else if (matrix.hasPerspective()) {
+        return GrQuadType::kPerspective;
+    } else {
+        return GrQuadType::kStandard;
+    }
+}
+
+// Perform minimal analysis of 'pts' (which are suitable for MakeFromSkQuad), and determine a
+// quad type that will be as minimally general as possible.
+static GrQuadType quad_type_for_points(const SkPoint pts[4], const SkMatrix& matrix) {
+    if (matrix.hasPerspective()) {
+        return GrQuadType::kPerspective;
+    }
+    // If 'pts' was formed by SkRect::toQuad() and not transformed further, it is safe to use the
+    // quad type derived from 'matrix'. Otherwise don't waste any more time and assume kStandard
+    // (most general 2D quad).
+    if ((pts[0].fX == pts[3].fX && pts[1].fX == pts[2].fX) &&
+        (pts[0].fY == pts[1].fY && pts[2].fY == pts[3].fY)) {
+        return quad_type_for_transformed_rect(matrix);
+    } else {
+        return GrQuadType::kStandard;
+    }
+}
+
 template <typename Q>
 void GrResolveAATypeForQuad(GrAAType requestedAAType, GrQuadAAFlags requestedEdgeFlags,
-                            const Q& quad, GrQuadType knownType,
-                            GrAAType* outAAType, GrQuadAAFlags* outEdgeFlags) {
+                            const Q& quad, GrAAType* outAAType, GrQuadAAFlags* outEdgeFlags) {
     // Most cases will keep the requested types unchanged
     *outAAType = requestedAAType;
     *outEdgeFlags = requestedEdgeFlags;
@@ -86,7 +115,7 @@
             } else {
                 // For coverage AA, if the quad is a rect and it lines up with pixel boundaries
                 // then overall aa and per-edge aa can be completely disabled
-                if (knownType == GrQuadType::kRect && !quad.aaHasEffectOnRect()) {
+                if (quad.quadType() == GrQuadType::kRect && !quad.aaHasEffectOnRect()) {
                     *outAAType = GrAAType::kNone;
                     *outEdgeFlags = GrQuadAAFlags::kNone;
                 }
@@ -107,58 +136,46 @@
 };
 
 // Instantiate GrResolve... for GrQuad and GrPerspQuad
-template void GrResolveAATypeForQuad(GrAAType, GrQuadAAFlags, const GrQuad&, GrQuadType,
+template void GrResolveAATypeForQuad(GrAAType, GrQuadAAFlags, const GrQuad&,
                                      GrAAType*, GrQuadAAFlags*);
-template void GrResolveAATypeForQuad(GrAAType, GrQuadAAFlags, const GrPerspQuad&, GrQuadType,
+template void GrResolveAATypeForQuad(GrAAType, GrQuadAAFlags, const GrPerspQuad&,
                                      GrAAType*, GrQuadAAFlags*);
 
-GrQuadType GrQuadTypeForTransformedRect(const SkMatrix& matrix) {
-    if (matrix.rectStaysRect()) {
-        return GrQuadType::kRect;
-    } else if (matrix.preservesRightAngles()) {
-        return GrQuadType::kRectilinear;
-    } else if (matrix.hasPerspective()) {
-        return GrQuadType::kPerspective;
-    } else {
-        return GrQuadType::kStandard;
-    }
-}
-
-GrQuadType GrQuadTypeForPoints(const SkPoint pts[4], const SkMatrix& matrix) {
-    if (matrix.hasPerspective()) {
-        return GrQuadType::kPerspective;
-    }
-    // If 'pts' was formed by SkRect::toQuad() and not transformed further, it is safe to use the
-    // quad type derived from 'matrix'. Otherwise don't waste any more time and assume kStandard
-    // (most general 2D quad).
-    if ((pts[0].fX == pts[3].fX && pts[1].fX == pts[2].fX) &&
-        (pts[0].fY == pts[1].fY && pts[2].fY == pts[3].fY)) {
-        return GrQuadTypeForTransformedRect(matrix);
-    } else {
-        return GrQuadType::kStandard;
-    }
-}
-
 GrQuad GrQuad::MakeFromRect(const SkRect& rect, const SkMatrix& m) {
     V4f x, y;
     SkMatrix::TypeMask tm = m.getType();
+    GrQuadType type;
     if (tm <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
         map_rect_translate_scale(rect, m, &x, &y);
+        type = GrQuadType::kRect;
     } else {
         map_rect_general(rect, m, &x, &y, nullptr);
+        type = quad_type_for_transformed_rect(m);
+        if (type == GrQuadType::kPerspective) {
+            // While the matrix created perspective, the coordinates were projected to a 2D quad
+            // in map_rect_general since no w V4f was provided.
+            type = GrQuadType::kStandard;
+        }
     }
-    return GrQuad(x, y);
+    return GrQuad(x, y, type);
 }
 
 GrQuad GrQuad::MakeFromSkQuad(const SkPoint pts[4], const SkMatrix& matrix) {
     V4f xs, ys;
     rearrange_sk_to_gr_points(pts, &xs, &ys);
+    GrQuadType type = quad_type_for_points(pts, matrix);
+    if (type == GrQuadType::kPerspective) {
+        // While the matrix created perspective, the coordinates were projected to a 2D quad
+        // in map_rect_general since no w V4f was provided.
+        type = GrQuadType::kStandard;
+    }
+
     if (matrix.isIdentity()) {
-        return GrQuad(xs, ys);
+        return GrQuad(xs, ys, type);
     } else {
         V4f mx, my;
         map_quad_general(xs, ys, matrix, &mx, &my, nullptr);
-        return GrQuad(mx, my);
+        return GrQuad(mx, my, type);
     }
 }
 
@@ -167,7 +184,8 @@
 }
 
 // Private constructor used by GrQuadList to quickly fill in a quad's values from the channel arrays
-GrPerspQuad::GrPerspQuad(const float* xs, const float* ys, const float* ws) {
+GrPerspQuad::GrPerspQuad(const float* xs, const float* ys, const float* ws, GrQuadType type)
+        : fType(type) {
     memcpy(fX, xs, 4 * sizeof(float));
     memcpy(fY, ys, 4 * sizeof(float));
     memcpy(fW, ws, 4 * sizeof(float));
@@ -176,24 +194,28 @@
 GrPerspQuad GrPerspQuad::MakeFromRect(const SkRect& rect, const SkMatrix& m) {
     V4f x, y, w;
     SkMatrix::TypeMask tm = m.getType();
+    GrQuadType type;
     if (tm <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
         map_rect_translate_scale(rect, m, &x, &y);
         w = 1.f;
+        type = GrQuadType::kRect;
     } else {
         map_rect_general(rect, m, &x, &y, &w);
+        type = quad_type_for_transformed_rect(m);
     }
-    return GrPerspQuad(x, y, w);
+    return GrPerspQuad(x, y, w, type);
 }
 
 GrPerspQuad GrPerspQuad::MakeFromSkQuad(const SkPoint pts[4], const SkMatrix& matrix) {
     V4f xs, ys;
     rearrange_sk_to_gr_points(pts, &xs, &ys);
+    GrQuadType type = quad_type_for_points(pts, matrix);
     if (matrix.isIdentity()) {
-        return GrPerspQuad(xs, ys, 1.f);
+        return GrPerspQuad(xs, ys, 1.f, type);
     } else {
         V4f mx, my, mw;
         map_quad_general(xs, ys, matrix, &mx, &my, &mw);
-        return GrPerspQuad(mx, my, mw);
+        return GrPerspQuad(mx, my, mw, type);
     }
 }