Add SkShadowUtils::GetLocalBounds.

Generates a bounding rect that encompasses both shadows for a given path,
relative to the path local space.

Bug: skia:11146
Change-Id: Ib8edb1072ed9cbfe36285523330be95fdf661d6b
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/351922
Commit-Queue: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Yegor Jbanov <yjbanov@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/src/utils/SkShadowUtils.cpp b/src/utils/SkShadowUtils.cpp
index f65877e..4e30c40 100644
--- a/src/utils/SkShadowUtils.cpp
+++ b/src/utils/SkShadowUtils.cpp
@@ -564,34 +564,61 @@
                                    unPremulScale*spotB);
 }
 
-// Draw an offset spot shadow and outlining ambient shadow for the given path.
-void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, const SkPoint3& zPlaneParams,
-                               const SkPoint3& lightPos, SkScalar lightRadius,
-                               SkColor ambientColor, SkColor spotColor,
-                               uint32_t flags) {
-
+static bool fill_shadow_rec(const SkPath& path, const SkPoint3& zPlaneParams,
+                            const SkPoint3& lightPos, SkScalar lightRadius,
+                            SkColor ambientColor, SkColor spotColor,
+                            uint32_t flags, const SkMatrix& ctm, SkDrawShadowRec* rec) {
     SkPoint pt = { lightPos.fX, lightPos.fY };
     if (!SkToBool(flags & kDirectionalLight_ShadowFlag)) {
         // If light position is in device space, need to transform to local space
         // before applying to SkCanvas.
         SkMatrix inverse;
-        if (!canvas->getTotalMatrix().invert(&inverse)) {
-            return;
+        if (!ctm.invert(&inverse)) {
+            return false;
         }
         inverse.mapPoints(&pt, 1);
     }
 
+    rec->fZPlaneParams   = zPlaneParams;
+    rec->fLightPos       = { pt.fX, pt.fY, lightPos.fZ };
+    rec->fLightRadius    = lightRadius;
+    rec->fAmbientColor   = ambientColor;
+    rec->fSpotColor      = spotColor;
+    rec->fFlags          = flags;
+
+    return true;
+}
+
+// Draw an offset spot shadow and outlining ambient shadow for the given path.
+void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, const SkPoint3& zPlaneParams,
+                               const SkPoint3& lightPos, SkScalar lightRadius,
+                               SkColor ambientColor, SkColor spotColor,
+                               uint32_t flags) {
     SkDrawShadowRec rec;
-    rec.fZPlaneParams   = zPlaneParams;
-    rec.fLightPos       = { pt.fX, pt.fY, lightPos.fZ };
-    rec.fLightRadius    = lightRadius;
-    rec.fAmbientColor   = ambientColor;
-    rec.fSpotColor      = spotColor;
-    rec.fFlags          = flags;
+    if (!fill_shadow_rec(path, zPlaneParams, lightPos, lightRadius, ambientColor, spotColor,
+                         flags, canvas->getTotalMatrix(), &rec)) {
+        return;
+    }
 
     canvas->private_draw_shadow_rec(path, rec);
 }
 
+bool SkShadowUtils::GetLocalBounds(const SkMatrix& ctm, const SkPath& path,
+                                   const SkPoint3& zPlaneParams, const SkPoint3& lightPos,
+                                   SkScalar lightRadius, uint32_t flags, SkRect* bounds) {
+    SkDrawShadowRec rec;
+    if (!fill_shadow_rec(path, zPlaneParams, lightPos, lightRadius, SK_ColorBLACK, SK_ColorBLACK,
+                         flags, ctm, &rec)) {
+        return false;
+    }
+
+    SkDrawShadowMetrics::GetLocalBounds(path, rec, ctm, bounds);
+
+    return true;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+
 static bool validate_rec(const SkDrawShadowRec& rec) {
     return rec.fLightPos.isFinite() && rec.fZPlaneParams.isFinite() &&
            SkScalarIsFinite(rec.fLightRadius);