move shadows to device virtual
authorMike Reed <reed@google.com>
Wed, 17 May 2017 12:53:36 +0000 (08:53 -0400)
committerSkia Commit-Bot <skia-commit-bot@chromium.org>
Wed, 17 May 2017 13:40:42 +0000 (13:40 +0000)
This CL keeps the impl for each device backend in the
utils file for simplicity (shared helpers). Future CLs
may move into their respective impl as they become
more specialized.

Bug: skia:
Change-Id: I97ce6cdcc5106ebf4c84778f943cc32d0b7613c1
Reviewed-on: https://skia-review.googlesource.com/15893
Reviewed-by: Mike Klein <mtklein@chromium.org>
Commit-Queue: Mike Reed <reed@google.com>

17 files changed:
include/core/SkCanvas.h
include/utils/SkNWayCanvas.h
src/core/SkCanvas.cpp
src/core/SkColorSpaceXformCanvas.cpp
src/core/SkDevice.h
src/core/SkDrawShadowRec.h [new file with mode: 0644]
src/core/SkLiteDL.cpp
src/core/SkLiteDL.h
src/core/SkLiteRecorder.cpp
src/core/SkLiteRecorder.h
src/core/SkRecordDraw.cpp
src/core/SkRecorder.cpp
src/core/SkRecorder.h
src/core/SkRecords.h
src/gpu/SkGpuDevice.h
src/utils/SkNWayCanvas.cpp
src/utils/SkShadowUtils.cpp

index e03b4f3daf234168af6b341675c6c2a73f232431..8ab281814e222e66c5ec126ab449d98536eaccd4 100644 (file)
@@ -24,6 +24,7 @@ class SkData;
 class SkDraw;
 class SkDrawable;
 class SkDrawFilter;
+struct SkDrawShadowRec;
 class SkImage;
 class SkImageFilter;
 class SkLights;
@@ -1237,6 +1238,8 @@ public:
      */
     void temporary_internal_getRgnClip(SkRegion* region);
 
+    void private_draw_shadow_rec(const SkPath&, const SkDrawShadowRec&);
+
 protected:
     // default impl defers to getDevice()->newSurface(info)
     virtual sk_sp<SkSurface> onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props);
@@ -1331,6 +1334,7 @@ protected:
                                   const SkPaint* paint);
     virtual void onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
                                      const SkRect& dst, const SkPaint* paint);
+    virtual void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&);
 
     enum ClipEdgeStyle {
         kHard_ClipEdgeStyle,
index ba0745e42004f75e163bd87b558cac47360f1411..7701d50e263653f748c9be777145f50e7ced92a0 100644 (file)
@@ -71,6 +71,7 @@ protected:
     void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
                           const SkPaint*) override;
     void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override;
+    void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override;
 
     void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override;
     void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override;
index 10e2181aff125d52ac5c995855c41f6d6a59b8d7..afc1203e6bc47b210a32de16af37b0c3365be1f6 100644 (file)
@@ -1909,6 +1909,21 @@ void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
     }
 }
 
+void SkCanvas::private_draw_shadow_rec(const SkPath& path, const SkDrawShadowRec& rec) {
+    this->onDrawShadowRec(path, rec);
+}
+
+void SkCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
+    SkPaint paint;
+    const SkRect& pathBounds = path.getBounds();
+
+    LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, &pathBounds)
+    while (iter.next()) {
+        iter.fDevice->drawShadow(path, rec);
+    }
+    LOOPER_END
+}
+
 //////////////////////////////////////////////////////////////////////////////
 //  These are the virtual drawing methods
 //////////////////////////////////////////////////////////////////////////////
index 65297a1801ec1d55014e6f139876a1aeaa7fa5dd..530552862d95b90c16418cb63719342c16326124 100644 (file)
@@ -8,6 +8,7 @@
 #include "SkColorFilter.h"
 #include "SkColorSpaceXformCanvas.h"
 #include "SkColorSpaceXformer.h"
+#include "SkDrawShadowRec.h"
 #include "SkGradientShader.h"
 #include "SkImageFilter.h"
 #include "SkImagePriv.h"
@@ -217,7 +218,11 @@ public:
         fTarget->drawImageLattice(fXformer->apply(bitmap).get(), lattice, dst,
                                   MaybePaint(paint, fXformer.get()));
     }
-
+    void onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) override {
+        SkDrawShadowRec newRec(rec);
+        newRec.fColor = fXformer->apply(rec.fColor);
+        fTarget->private_draw_shadow_rec(path, newRec);
+    }
     void onDrawPicture(const SkPicture* pic,
                        const SkMatrix* matrix,
                        const SkPaint* paint) override {
index 17ccfdd198bc91352121dbb1fc96412de6fcb0f0..17ea6f71f7a0c150286dda7f25cecbd7e132feab 100644 (file)
@@ -15,6 +15,7 @@
 
 class SkBitmap;
 class SkDrawFilter;
+struct SkDrawShadowRec;
 class SkImageFilterCache;
 struct SkIRect;
 class SkMatrix;
@@ -234,6 +235,8 @@ protected:
                              const SkScalar pos[], int scalarsPerPos,
                              const SkPoint& offset, const SkPaint& paint) = 0;
     virtual void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) = 0;
+    virtual void drawShadow(const SkPath&, const SkDrawShadowRec&);
+
     // default implementation unrolls the blob runs.
     virtual void drawTextBlob(const SkTextBlob*, SkScalar x, SkScalar y,
                               const SkPaint& paint, SkDrawFilter* drawFilter);
diff --git a/src/core/SkDrawShadowRec.h b/src/core/SkDrawShadowRec.h
new file mode 100644 (file)
index 0000000..19199c0
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkDrawShadowRec_DEFINED
+#define SkDrawShadowRec_DEFINED
+
+#include "SkPath.h"
+
+struct SkDrawShadowRec {
+    SkPoint3    fZPlaneParams;
+    SkPoint3    fLightPos;
+    SkScalar    fLightRadius;
+    float       fAmbientAlpha;
+    float       fSpotAlpha;
+    SkColor     fColor;
+    uint32_t    fFlags;
+};
+
+#endif
index b3149a7d424630833878ead3c407f25e890be09c..f1101b1be2ca70f827983d32626d90b5373e836c 100644 (file)
@@ -8,6 +8,7 @@
 #include "SkCanvas.h"
 #include "SkData.h"
 #include "SkDrawFilter.h"
+#include "SkDrawShadowRec.h"
 #include "SkImage.h"
 #include "SkImageFilter.h"
 #include "SkLiteDL.h"
@@ -55,7 +56,7 @@ namespace {
     M(DrawImage) M(DrawImageNine) M(DrawImageRect) M(DrawImageLattice)          \
     M(DrawText) M(DrawPosText) M(DrawPosTextH)                                  \
     M(DrawTextOnPath) M(DrawTextRSXform) M(DrawTextBlob)                        \
-    M(DrawPatch) M(DrawPoints) M(DrawVertices) M(DrawAtlas)
+    M(DrawPatch) M(DrawPoints) M(DrawVertices) M(DrawAtlas) M(DrawShadowRec)
 
 #define M(T) T,
     enum class Type : uint8_t { TYPES(M) };
@@ -477,6 +478,17 @@ namespace {
                          maybe_unset(cull), &paint);
         }
     };
+    struct DrawShadowRec final : Op {
+        static const auto kType = Type::DrawShadowRec;
+        DrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec)
+            : fPath(path), fRec(rec)
+        {}
+        SkPath          fPath;
+        SkDrawShadowRec fRec;
+        void draw(SkCanvas* c, const SkMatrix&) const {
+            c->private_draw_shadow_rec(fPath, fRec);
+        }
+    };
 }
 
 template <typename T, typename... Args>
@@ -662,6 +674,9 @@ void SkLiteDL::drawAtlas(const SkImage* atlas, const SkRSXform xforms[], const S
                   texs, count,
                 colors, colors ? count : 0);
 }
+void SkLiteDL::drawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
+    this->push<DrawShadowRec>(0, path, rec);
+}
 
 typedef void(*draw_fn)(const void*,  SkCanvas*, const SkMatrix&);
 typedef void(*void_fn)(const void*);
index c5df35095706c25f2c79d1c4fbc12f0cd14270f6..31ef38e6bf42ed0cb794e445e10f223c74fcac16 100644 (file)
@@ -77,6 +77,7 @@ public:
     void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&);
     void drawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int,
                    SkBlendMode, const SkRect*, const SkPaint*);
+    void drawShadowRec(const SkPath&, const SkDrawShadowRec&);
 
 private:
     template <typename T, typename... Args>
index 5affb3d4ab1fee47384382dd3a76e59b1249f6d2..dbee48e1bd3bbe4fd63df9d3f2d5ca58a7a19d2a 100644 (file)
@@ -194,3 +194,6 @@ void SkLiteRecorder::onDrawAtlas(const SkImage* atlas,
                                  const SkPaint* paint) {
     fDL->drawAtlas(atlas, xforms, texs, colors, count, bmode, cull, paint);
 }
+void SkLiteRecorder::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
+    fDL->drawShadowRec(path, rec);
+}
index 3c156af7217ce1890eaa6c05e3bf2500ef47f8d5..4d49eb5336e37fc5d925b3978eddc523976747be 100644 (file)
@@ -77,6 +77,7 @@ public:
     void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override;
     void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[],
                      int, SkBlendMode, const SkRect*, const SkPaint*) override;
+    void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override;
 
 private:
     typedef SkNoDrawCanvas INHERITED;
index e668cc874c3402808920c85c4e0c9caaddf675b3..953e87485428e33d806ba267365709b2d9904324 100644 (file)
@@ -125,6 +125,7 @@ DRAW(DrawTextRSXform, drawTextRSXform(r.text, r.byteLength, r.xforms, r.cull, r.
 DRAW(DrawAtlas, drawAtlas(r.atlas.get(),
                           r.xforms, r.texs, r.colors, r.count, r.mode, r.cull, r.paint));
 DRAW(DrawVertices, drawVertices(r.vertices, r.bmode, r.paint));
+DRAW(DrawShadowRec, private_draw_shadow_rec(r.path, r.rec));
 DRAW(DrawAnnotation, drawAnnotation(r.rect, r.key.c_str(), r.value.get()));
 #undef DRAW
 
@@ -455,6 +456,10 @@ private:
         }
     }
 
+    Bounds bounds(const DrawShadowRec& op) const {
+        return this->adjustAndMap(op.path.getBounds(), nullptr);
+    }
+
     Bounds bounds(const DrawPicture& op) const {
         SkRect dst = op.picture->cullRect();
         op.matrix.mapRect(&dst);
index 64d613df967699906a235d0f411fe40a8cb4134a..1eeef532e6a5806fa1ccfa2b2e4f912f16c165f3 100644 (file)
@@ -338,6 +338,10 @@ void SkRecorder::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], cons
            this->copy(cull));
 }
 
+void SkRecorder::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
+    APPEND(DrawShadowRec, path, rec);
+}
+
 void SkRecorder::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
     APPEND(DrawAnnotation, rect, SkString(key), sk_ref_sp(value));
 }
index 53449346652f548346e26ae27df1ce882d8f273a..04e75edd26da16364cfdc9c804b6a92272239460 100644 (file)
@@ -121,6 +121,7 @@ public:
     void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override;
     void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[],
                      int count, SkBlendMode, const SkRect* cull, const SkPaint*) override;
+    void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override;
 
     void onClipRect(const SkRect& rect, SkClipOp, ClipEdgeStyle) override;
     void onClipRRect(const SkRRect& rrect, SkClipOp, ClipEdgeStyle) override;
index 6af4aad3f559a211ad11420d80cab93afce2ca9c..a63ef1c6a5b4c010f668dc60165707253033734a 100644 (file)
@@ -11,6 +11,7 @@
 #include "SkData.h"
 #include "SkCanvas.h"
 #include "SkDrawable.h"
+#include "SkDrawShadowRec.h"
 #include "SkImage.h"
 #include "SkImageFilter.h"
 #include "SkMatrix.h"
@@ -80,6 +81,7 @@ namespace SkRecords {
     M(DrawTextBlob)                                                 \
     M(DrawAtlas)                                                    \
     M(DrawVertices)                                                 \
+    M(DrawShadowRec)                                                \
     M(DrawAnnotation)
 
 // Defines SkRecords::Type, an enum of all record types.
@@ -345,6 +347,9 @@ RECORD(DrawVertices, kDraw_Tag|kHasPaint_Tag,
         SkPaint paint;
         sk_sp<SkVertices> vertices;
         SkBlendMode bmode);
+RECORD(DrawShadowRec, kDraw_Tag,
+       SkPath path;
+       SkDrawShadowRec rec);
 RECORD(DrawAnnotation, 0,  // TODO: kDraw_Tag, skia:5548
        SkRect rect;
        SkString key;
index 340f39a072873db2f1faa673a465af4cc27a8873..0b60a965161c8238f8ef8991712c68bc1b1f3226 100644 (file)
@@ -92,6 +92,7 @@ public:
     void drawTextBlob(const SkTextBlob*, SkScalar x, SkScalar y,
                       const SkPaint& paint, SkDrawFilter* drawFilter) override;
     void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override;
+    void drawShadow(const SkPath&, const SkDrawShadowRec&) override;
     void drawAtlas(const SkImage* atlas, const SkRSXform[], const SkRect[],
                    const SkColor[], int count, SkBlendMode, const SkPaint&) override;
     void drawDevice(SkBaseDevice*, int x, int y, const SkPaint&) override;
index 4f6ad46d8505466da35da42fc2ae6dd310968105..208f3b4719c3c92c5dcdc6fcab93fe19b0b1c25f 100644 (file)
@@ -299,6 +299,13 @@ void SkNWayCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4]
     }
 }
 
+void SkNWayCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
+    Iter iter(fList);
+    while (iter.next()) {
+        iter->private_draw_shadow_rec(path, rec);
+    }
+}
+
 void SkNWayCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* data) {
     Iter iter(fList);
     while (iter.next()) {
index 806c98e68b1cab9a1829d388d7a7e305fc075051..f0ab230acc05ddfa52f40b63031b0a460688b21e 100644 (file)
@@ -9,6 +9,8 @@
 #include "SkCanvas.h"
 #include "SkColorFilter.h"
 #include "SkColorPriv.h"
+#include "SkDevice.h"
+#include "SkDrawShadowRec.h"
 #include "SkPath.h"
 #include "SkPM4f.h"
 #include "SkRandom.h"
@@ -20,9 +22,9 @@
 #if SK_SUPPORT_GPU
 #include "GrShape.h"
 #include "effects/GrBlurredEdgeFragmentProcessor.h"
-#endif
 #include "../../src/effects/shadows/SkAmbientShadowMaskFilter.h"
 #include "../../src/effects/shadows/SkSpotShadowMaskFilter.h"
+#endif
 
 /**
 *  Gaussian color filter -- produces a Gaussian ramp based on the color's B value,
@@ -444,7 +446,9 @@ static void* kNamespace;
  * they are first found in SkResourceCache.
  */
 template <typename FACTORY>
-void draw_shadow(const FACTORY& factory, SkCanvas* canvas, ShadowedPath& path, SkColor color) {
+    void draw_shadow(const FACTORY& factory,
+                     std::function<void(const SkVertices*, SkBlendMode, const SkPaint&,
+                     SkScalar tx, SkScalar ty)> drawProc, ShadowedPath& path, SkColor color) {
     FindContext<FACTORY> context(&path.viewMatrix(), &factory);
 
     SkResourceCache::Key* key = nullptr;
@@ -496,82 +500,83 @@ void draw_shadow(const FACTORY& factory, SkCanvas* canvas, ShadowedPath& path, S
     paint.setColorFilter(SkColorFilter::MakeComposeFilter(
             SkColorFilter::MakeModeFilter(color, SkBlendMode::kModulate),
             SkGaussianColorFilter::Make()));
-    if (translate->fX || translate->fY) {
-        canvas->save();
-        canvas->translate(translate->fX, translate->fY);
-    }
-    canvas->drawVertices(vertices, SkBlendMode::kModulate, paint);
-    if (translate->fX || translate->fY) {
-        canvas->restore();
-    }
+
+    drawProc(vertices.get(), SkBlendMode::kModulate, paint, translate->fX, translate->fY);
 }
 }
 
-static bool draw_analytic_shadows(SkCanvas* canvas, const SkPath& path, SkScalar occluderZ,
-                                  const SkPoint3& devLightPos, SkScalar lightRadius,
-                                  SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color,
-                                  uint32_t flags) {
-    // only supported in GPU code
-    if (!canvas->getGrContext()) {
-        return false;
-    }
+static bool tilted(const SkPoint3& zPlaneParams) {
+    return !SkScalarNearlyZero(zPlaneParams.fX) || !SkScalarNearlyZero(zPlaneParams.fY);
+}
+
+static SkPoint3 map(const SkMatrix& m, const SkPoint3& pt) {
+    SkPoint3 result;
+    m.mapXY(pt.fX, pt.fY, (SkPoint*)&result.fX);
+    result.fZ = pt.fZ;
+    return result;
+}
+
+#if SK_SUPPORT_GPU
+#include "SkGpuDevice.h"
+void SkGpuDevice::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
+    // check z plane
+    bool tiltZPlane = tilted(rec.fZPlaneParams);
+    bool skipAnalytic = SkToBool(rec.fFlags & SkShadowFlags::kGeometricOnly_ShadowFlag);
+
+    const SkMatrix& ctm = this->ctm();
 
-    SkRect rect;
-    SkRRect rrect;
-    const SkMatrix& ctm = canvas->getTotalMatrix();
-    if (ctm.rectStaysRect() && ctm.isSimilarity()) {
+    if (!tiltZPlane && !skipAnalytic && ctm.rectStaysRect() && ctm.isSimilarity()) {
+        SkPoint3 devLightPos = map(ctm, rec.fLightPos);
+
+        const SkScalar occluderZ = rec.fZPlaneParams.fZ;
+        SkPaint ambientPaint, spotPaint;
+        ambientPaint.setColor(rec.fColor);
+        spotPaint.setColor(rec.fColor);
+        if (rec.fAmbientAlpha > 0) {
+            ambientPaint.setMaskFilter(SkAmbientShadowMaskFilter::Make(occluderZ, rec.fAmbientAlpha,
+                                                                       rec.fFlags));
+        }
+        if (rec.fSpotAlpha > 0) {
+            spotPaint.setMaskFilter(SkSpotShadowMaskFilter::Make(occluderZ, devLightPos,
+                                                                 rec.fLightRadius, rec.fSpotAlpha,
+                                                                 rec.fFlags));
+        }
+
+        SkRect rect;
+        SkRRect rrect;
         if (path.isRect(&rect)) {
-            SkPaint newPaint;
-            newPaint.setColor(color);
-            if (ambientAlpha > 0) {
-                newPaint.setMaskFilter(SkAmbientShadowMaskFilter::Make(occluderZ,
-                                                                       ambientAlpha, flags));
-                canvas->drawRect(rect, newPaint);
+            if (rec.fAmbientAlpha > 0) {
+                this->drawRect(rect, ambientPaint);
             }
-            if (spotAlpha > 0) {
-                newPaint.setMaskFilter(SkSpotShadowMaskFilter::Make(occluderZ, devLightPos,
-                                                                    lightRadius, spotAlpha,
-                                                                    flags));
-                canvas->drawRect(rect, newPaint);
+            if (rec.fSpotAlpha > 0) {
+                this->drawRect(rect, spotPaint);
             }
-            return true;
+            return;
         } else if (path.isRRect(&rrect) && rrect.isSimpleCircular() &&
                    rrect.radii(SkRRect::kUpperLeft_Corner).fX > SK_ScalarNearlyZero) {
-            SkPaint newPaint;
-            newPaint.setColor(color);
-            if (ambientAlpha > 0) {
-                newPaint.setMaskFilter(SkAmbientShadowMaskFilter::Make(occluderZ,
-                                                                       ambientAlpha, flags));
-                canvas->drawRRect(rrect, newPaint);
+            if (rec.fAmbientAlpha > 0) {
+                this->drawRRect(rrect, ambientPaint);
             }
-            if (spotAlpha > 0) {
-                newPaint.setMaskFilter(SkSpotShadowMaskFilter::Make(occluderZ, devLightPos,
-                                                                    lightRadius, spotAlpha,
-                                                                    flags));
-                canvas->drawRRect(rrect, newPaint);
+            if (rec.fSpotAlpha > 0) {
+                this->drawRRect(rrect, spotPaint);
             }
-            return true;
+            return;
         } else if (path.isOval(&rect) && SkScalarNearlyEqual(rect.width(), rect.height()) &&
                    rect.width() > SK_ScalarNearlyZero) {
-            SkPaint newPaint;
-            newPaint.setColor(color);
-            if (ambientAlpha > 0) {
-                newPaint.setMaskFilter(SkAmbientShadowMaskFilter::Make(occluderZ,
-                                                                       ambientAlpha, flags));
-                canvas->drawOval(rect, newPaint);
+            if (rec.fAmbientAlpha > 0) {
+                this->drawOval(rect, ambientPaint);
             }
-            if (spotAlpha > 0) {
-                newPaint.setMaskFilter(SkSpotShadowMaskFilter::Make(occluderZ, devLightPos,
-                                                                    lightRadius, spotAlpha,
-                                                                    flags));
-                canvas->drawOval(rect, newPaint);
+            if (rec.fSpotAlpha > 0) {
+                this->drawOval(rect, spotPaint);
             }
-            return true;
+            return;
         }
     }
 
-    return false;
+    // failed to find an accelerated case
+    this->INHERITED::drawShadow(path, rec);
 }
+#endif
 
 static SkColor compute_render_color(SkColor color, float alpha) {
     return SkColorSetARGB(alpha*SkColorGetA(color), SkColorGetR(color),
@@ -583,26 +588,47 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, const SkPoi
                                const SkPoint3& devLightPos, SkScalar lightRadius,
                                SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color,
                                uint32_t flags) {
-    // check z plane
-    bool tiltZPlane = !SkScalarNearlyZero(zPlaneParams.fX) || !SkScalarNearlyZero(zPlaneParams.fY);
-
-    // try fast paths
-    bool skipAnalytic = SkToBool(flags & SkShadowFlags::kGeometricOnly_ShadowFlag) || tiltZPlane;
-    if (!skipAnalytic && draw_analytic_shadows(canvas, path, zPlaneParams.fZ, devLightPos,
-                                               lightRadius, ambientAlpha, spotAlpha, color,
-                                               flags)) {
+    SkMatrix inverse;
+    if (!canvas->getTotalMatrix().invert(&inverse)) {
         return;
     }
+    SkPoint pt = inverse.mapXY(devLightPos.fX, devLightPos.fY);
+
+    SkDrawShadowRec rec;
+    rec.fZPlaneParams   = zPlaneParams;
+    rec.fLightPos       = { pt.fX, pt.fY, devLightPos.fZ };
+    rec.fLightRadius    = lightRadius;
+    rec.fAmbientAlpha   = SkScalarToFloat(ambientAlpha);
+    rec.fSpotAlpha      = SkScalarToFloat(spotAlpha);
+    rec.fColor          = color;
+    rec.fFlags          = flags;
+
+    canvas->private_draw_shadow_rec(path, rec);
+}
+
+void SkBaseDevice::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
+    auto drawVertsProc = [this](const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint,
+                                SkScalar tx, SkScalar ty) {
+        SkAutoDeviceCTMRestore adr(this, SkMatrix::Concat(this->ctm(),
+                                                          SkMatrix::MakeTrans(tx, ty)));
+        this->drawVertices(vertices, mode, paint);
+    };
 
-    SkAutoCanvasRestore acr(canvas, true);
-    SkMatrix viewMatrix = canvas->getTotalMatrix();
-    canvas->resetMatrix();
+    SkMatrix viewMatrix = this->ctm();
+    SkAutoDeviceCTMRestore adr(this, SkMatrix::I());
 
     ShadowedPath shadowedPath(&path, &viewMatrix);
 
-    bool transparent = SkToBool(flags & SkShadowFlags::kTransparentOccluder_ShadowFlag);
+    bool tiltZPlane = tilted(rec.fZPlaneParams);
+    bool transparent = SkToBool(rec.fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag);
     bool uncached = tiltZPlane || path.isVolatile();
 
+    SkColor color = rec.fColor;
+    SkPoint3 zPlaneParams = rec.fZPlaneParams;
+    SkPoint3 devLightPos = map(viewMatrix, rec.fLightPos);
+    float lightRadius = rec.fLightRadius;
+
+    float ambientAlpha = rec.fAmbientAlpha;
     if (ambientAlpha > 0) {
         ambientAlpha = SkTMin(ambientAlpha, 1.f);
         if (uncached) {
@@ -614,19 +640,20 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, const SkPoi
             // Run the vertex color through a GaussianColorFilter and then modulate the grayscale
             // result of that against our 'color' param.
             paint.setColorFilter(SkColorFilter::MakeComposeFilter(
-                SkColorFilter::MakeModeFilter(renderColor, SkBlendMode::kModulate),
-                SkGaussianColorFilter::Make()));
-            canvas->drawVertices(vertices, SkBlendMode::kModulate, paint);
+                                                                  SkColorFilter::MakeModeFilter(renderColor, SkBlendMode::kModulate),
+                                                                  SkGaussianColorFilter::Make()));
+            this->drawVertices(vertices.get(), SkBlendMode::kModulate, paint);
         } else {
             AmbientVerticesFactory factory;
             factory.fOccluderHeight = zPlaneParams.fZ;
             factory.fTransparent = transparent;
 
             SkColor renderColor = compute_render_color(color, ambientAlpha);
-            draw_shadow(factory, canvas, shadowedPath, renderColor);
+            draw_shadow(factory, drawVertsProc, shadowedPath, renderColor);
         }
     }
 
+    float spotAlpha = rec.fSpotAlpha;
     if (spotAlpha > 0) {
         spotAlpha = SkTMin(spotAlpha, 1.f);
         if (uncached) {
@@ -641,7 +668,7 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, const SkPoi
             paint.setColorFilter(SkColorFilter::MakeComposeFilter(
                 SkColorFilter::MakeModeFilter(renderColor, SkBlendMode::kModulate),
                 SkGaussianColorFilter::Make()));
-            canvas->drawVertices(vertices, SkBlendMode::kModulate, paint);
+            this->drawVertices(vertices.get(), SkBlendMode::kModulate, paint);
         } else {
             SpotVerticesFactory factory;
             SkScalar occluderHeight = zPlaneParams.fZ;
@@ -690,7 +717,7 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, const SkPoi
             }
 #endif
             SkColor renderColor = compute_render_color(color, spotAlpha);
-            draw_shadow(factory, canvas, shadowedPath, renderColor);
+            draw_shadow(factory, drawVertsProc, shadowedPath, renderColor);
         }
     }
 }