For vertices/patches with a shader and no texCoords, use positions

This was another surprising (to me) inconsistency. Just because these
geometric primitives allow for explicit local coords, doesn't mean we
should require them (vs. all others that implicitly sample using local
position).

Change-Id: If3e7f6077bd15891b06cd2ffc969f1a649305d42
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/290130
Reviewed-by: Mike Reed <reed@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt
index 0d0f512..bcb29c4 100644
--- a/RELEASE_NOTES.txt
+++ b/RELEASE_NOTES.txt
@@ -9,6 +9,11 @@
 
   * <insert new release notes here>
 
+  * SkCanvas::drawVertices and drawPatch now support mapping an SkShader without explicit
+    texture coordinates. If they're not supplied, the local positions (vertex position or
+    patch cubic positions) will be directly used to sample the SkShader.
+    https://review.skia.org/290130
+
 * * *
 
 Milestone 84
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index 975aab0..440d9b5 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -2164,8 +2164,11 @@
     }
 
     /** Draws SkVertices vertices, a triangle mesh, using clip and SkMatrix.
-        If vertices texs and vertices colors are defined in vertices, and SkPaint paint
-        contains SkShader, SkBlendMode mode combines vertices colors with SkShader.
+        If paint contains an SkShader and vertices does not contain texCoords, the shader
+        is mapped using the vertices' positions.
+
+        If vertices colors are defined in vertices, and SkPaint paint contains SkShader,
+        SkBlendMode mode combines vertices colors with SkShader.
 
         @param vertices  triangle mesh to draw
         @param mode      combines vertices colors with SkShader, if both are present
@@ -2183,8 +2186,11 @@
     }
 
     /** Draws SkVertices vertices, a triangle mesh, using clip and SkMatrix.
-        If vertices texs and vertices colors are defined in vertices, and SkPaint paint
-        contains SkShader, SkBlendMode mode combines vertices colors with SkShader.
+        If paint contains an SkShader and vertices does not contain texCoords, the shader
+        is mapped using the vertices' positions.
+
+        If vertices colors are defined in vertices, and SkPaint paint contains SkShader,
+        SkBlendMode mode combines vertices colors with SkShader.
 
         @param vertices  triangle mesh to draw
         @param mode      combines vertices colors with SkShader, if both are present
@@ -2217,7 +2223,8 @@
         bottom-right, bottom-left order.
 
         If paint contains SkShader, SkPoint array texCoords maps SkShader as texture to
-        corners in top-left, top-right, bottom-right, bottom-left order.
+        corners in top-left, top-right, bottom-right, bottom-left order. If texCoords is
+        nullptr, SkShader is mapped using positions (derived from cubics).
 
         @param cubics     SkPath cubic array, sharing common points
         @param colors     color array, one for each corner
@@ -2245,7 +2252,8 @@
         bottom-right, bottom-left order.
 
         If paint contains SkShader, SkPoint array texCoords maps SkShader as texture to
-        corners in top-left, top-right, bottom-right, bottom-left order.
+        corners in top-left, top-right, bottom-right, bottom-left order. If texCoords is
+        nullptr, SkShader is mapped using positions (derived from cubics).
 
         @param cubics     SkPath cubic array, sharing common points
         @param colors     color array, one for each corner
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 78a36e4..65eb6fe 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -1967,6 +1967,17 @@
         }
     }
 
+#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
+    // Preserve legacy behavior for Android: ignore the SkShader if there are no texCoords present
+    if (paint.getShader() &&
+        !(vertices->priv().hasTexCoords() || vertices->priv().hasCustomData())) {
+        SkPaint noShaderPaint(paint);
+        noShaderPaint.setShader(nullptr);
+        this->onDrawVerticesObject(vertices, mode, noShaderPaint);
+        return;
+    }
+#endif
+
     this->onDrawVerticesObject(vertices, mode, paint);
 }
 
diff --git a/src/core/SkDraw_vertices.cpp b/src/core/SkDraw_vertices.cpp
index 9f605db..fd36f39 100644
--- a/src/core/SkDraw_vertices.cpp
+++ b/src/core/SkDraw_vertices.cpp
@@ -268,11 +268,13 @@
     const uint16_t* indices = info.indices();
     const SkColor* colors = info.colors();
 
-    // make textures and shader mutually consistent
+    // No need for texCoords without shader. If shader is present without explicit texCoords,
+    // use positions instead.
     SkShader* shader = paint.getShader();
-    if (!(shader && textures)) {
-        shader = nullptr;
+    if (!shader) {
         textures = nullptr;
+    } else if (!textures) {
+        textures = positions;
     }
 
     // We can simplify things for certain blendmodes. This is for speed, and SkComposeShader
@@ -351,6 +353,14 @@
                                 // all opaque (and the blendmode will keep them that way
         }
 
+        // Positions as texCoords? The local matrix is always identity, so update once
+        if (textures == positions) {
+            SkMatrix localM;
+            if (!updater->update(ctm, &localM)) {
+                return;
+            }
+        }
+
         auto blitter = SkCreateRasterPipelineBlitter(fDst, p, pipeline, isOpaque, outerAlloc,
                                                      fRC->clipShader());
         while (vertProc(&state)) {
@@ -360,9 +370,9 @@
             }
 
             SkMatrix localM;
-            if (texture_to_matrix(state, positions, textures, &localM) &&
-                updater->update(ctm, &localM))
-            {
+            if ((textures == positions) ||
+                (texture_to_matrix(state, positions, textures, &localM) &&
+                 updater->update(ctm, &localM))) {
                 fill_triangle(state, blitter, *fRC, dev2, dev3);
             }
         }
@@ -378,7 +388,7 @@
 
             const SkMatrixProvider* matrixProvider = fMatrixProvider;
             SkTLazy<SkPreConcatMatrixProvider> preConcatMatrixProvider;
-            if (textures) {
+            if (textures && (textures != positions)) {
                 SkMatrix localM;
                 if (!texture_to_matrix(state, positions, textures, &localM)) {
                     continue;
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 132e67f..df273f6 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -940,12 +940,11 @@
                                 const SkPaint& skPaint,
                                 const SkMatrixProvider& matrixProvider,
                                 SkBlendMode bmode,
-                                bool hasTexs,
                                 bool hasColors,
                                 GrPaint* grPaint) {
-    if (hasTexs && skPaint.getShader()) {
+    if (skPaint.getShader()) {
         if (hasColors) {
-            // When there are texs and colors the shader and colors are combined using bmode.
+            // When there are colors and a shader, the shader and colors are combined using bmode.
             return SkPaintToGrPaintWithXfermode(context, colorInfo, skPaint, matrixProvider, bmode,
                                                 grPaint);
         } else {
@@ -954,12 +953,11 @@
         }
     } else {
         if (hasColors) {
-            // We have colors, but either have no shader or no texture coords (which implies that
-            // we should ignore the shader).
+            // We have colors, but no shader.
             return SkPaintToGrPaintWithPrimitiveColor(context, colorInfo, skPaint, matrixProvider,
                                                       grPaint);
         } else {
-            // No colors and no shaders. Just draw with the paint color.
+            // No colors and no shader. Just draw with the paint color.
             return SkPaintToGrPaintNoShader(context, colorInfo, skPaint, matrixProvider, grPaint);
         }
     }
@@ -975,13 +973,9 @@
     const SkRuntimeEffect* effect =
             paint.getShader() ? as_SB(paint.getShader())->asRuntimeEffect() : nullptr;
 
-    // Pretend that we have tex coords when using custom per-vertex data. The shader is going to
-    // use those (rather than local coords), but our paint conversion remains the same.
     GrPaint grPaint;
-    bool hasColors = info.hasColors();
-    bool hasTexs = info.hasTexCoords() || info.hasCustomData();
     if (!init_vertices_paint(fContext.get(), fRenderTargetContext->colorInfo(), paint,
-                             this->asMatrixProvider(), mode, hasTexs, hasColors, &grPaint)) {
+                             this->asMatrixProvider(), mode, info.hasColors(), &grPaint)) {
         return;
     }
     fRenderTargetContext->drawVertices(this->clip(), std::move(grPaint), this->asMatrixProvider(),