Initial clipShader implementation for SkClipStack and GPU

Change-Id: I0af800900a7fbd9d16af0058ee0754358ebc3875
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/293562
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/src/shaders/SkLocalMatrixShader.cpp b/src/shaders/SkLocalMatrixShader.cpp
index 66ee52b..cc95a30 100644
--- a/src/shaders/SkLocalMatrixShader.cpp
+++ b/src/shaders/SkLocalMatrixShader.cpp
@@ -12,6 +12,7 @@
 
 #if SK_SUPPORT_GPU
 #include "src/gpu/GrFragmentProcessor.h"
+#include "src/gpu/effects/generated/GrDeviceSpaceEffect.h"
 #endif
 
 #if SK_SUPPORT_GPU
@@ -172,8 +173,23 @@
 #if SK_SUPPORT_GPU
 std::unique_ptr<GrFragmentProcessor> SkCTMShader::asFragmentProcessor(
         const GrFPArgs& args) const {
-    return as_SB(fProxyShader)->asFragmentProcessor(
-        GrFPArgs::WithPreLocalMatrix(args, this->getLocalMatrix()));
+    SkMatrix ctmInv;
+    if (!fCTM.invert(&ctmInv)) {
+        return nullptr;
+    }
+
+    auto ctmProvider = SkOverrideDeviceMatrixProvider(args.fMatrixProvider, fCTM);
+    auto base = as_SB(fProxyShader)->asFragmentProcessor(
+        GrFPArgs::WithPreLocalMatrix(args.withNewMatrixProvider(ctmProvider),
+                                     this->getLocalMatrix()));
+    if (!base) {
+        return nullptr;
+    }
+
+    // In order for the shader to be evaluated with the original CTM, we explicitly evaluate it
+    // at sk_FragCoord, and pass that through the inverse of the original CTM. This avoids requiring
+    // local coords for the shader and mapping from the draw's local to device and then back.
+    return GrDeviceSpaceEffect::Make(std::move(base), ctmInv);
 }
 #endif
 
@@ -183,6 +199,5 @@
 }
 
 sk_sp<SkShader> SkShaderBase::makeWithCTM(const SkMatrix& postM) const {
-    return postM.isIdentity() ? sk_ref_sp(this)
-                              : sk_sp<SkShader>(new SkCTMShader(sk_ref_sp(this), postM));
+    return sk_sp<SkShader>(new SkCTMShader(sk_ref_sp(this), postM));
 }