Return translate info from looper, rather than moding a canvas

Change-Id: Ibb4520030bc0ca455fa079d923fd4f5be86d72a1
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/229837
Reviewed-by: Florin Malita <fmalita@chromium.org>
Commit-Queue: Mike Reed <reed@google.com>
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index bdb0e82..762af67 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -421,7 +421,8 @@
 
 #ifdef SK_SUPPORT_LEGACY_DRAWLOOPER
         if (SkDrawLooper* looper = paint.getLooper()) {
-            fLooperContext = looper->makeContext(canvas, &fAlloc);
+            fLooperContext = looper->makeContext(&fAlloc);
+            fCanvas->save();
             fIsSimple = false;
         } else
 #endif
@@ -491,9 +492,15 @@
         paint->setBlendMode(SkBlendMode::kSrcOver);
     }
 
-    if (fLooperContext && !fLooperContext->next(fCanvas, paint)) {
-        fDone = true;
-        return false;
+    if (fLooperContext) {
+        fCanvas->restore();
+        SkDrawLooper::Context::Info info;
+        if (!fLooperContext->next(&info, paint)) {
+            fDone = true;
+            return false;
+        }
+        fCanvas->save();
+        info.applyToCanvas(fCanvas);
     }
     fPaint = paint;
 
diff --git a/src/core/SkDrawLooper.cpp b/src/core/SkDrawLooper.cpp
index 6aa082a..11dee29 100644
--- a/src/core/SkDrawLooper.cpp
+++ b/src/core/SkDrawLooper.cpp
@@ -12,14 +12,32 @@
 #include "include/core/SkRect.h"
 #include "src/core/SkArenaAlloc.h"
 
+void SkDrawLooper::Context::Info::applyToCTM(SkMatrix* ctm) const {
+    if (fApplyPostCTM) {
+        ctm->postTranslate(fTranslate.fX, fTranslate.fY);
+    } else {
+        ctm->preTranslate(fTranslate.fX, fTranslate.fY);
+    }
+}
+
+void SkDrawLooper::Context::Info::applyToCanvas(SkCanvas* canvas) const {
+    if (fApplyPostCTM) {
+        SkMatrix ctm = canvas->getTotalMatrix();
+        ctm.postTranslate(fTranslate.fX, fTranslate.fY);
+        canvas->setMatrix(ctm);
+    } else {
+        canvas->translate(fTranslate.fX, fTranslate.fY);
+    }
+}
+
 bool SkDrawLooper::canComputeFastBounds(const SkPaint& paint) const {
-    SkCanvas canvas;
     SkSTArenaAlloc<48> alloc;
 
-    SkDrawLooper::Context* context = this->makeContext(&canvas, &alloc);
+    SkDrawLooper::Context* context = this->makeContext(&alloc);
     for (;;) {
         SkPaint p(paint);
-        if (context->next(&canvas, &p)) {
+        SkDrawLooper::Context::Info info;
+        if (context->next(&info, &p)) {
 #ifdef SK_SUPPORT_LEGACY_DRAWLOOPER
             p.setLooper(nullptr);
 #endif
@@ -38,22 +56,22 @@
     // src and dst rects may alias and we need to keep the original src, so copy it.
     const SkRect src = s;
 
-    SkCanvas canvas;
     SkSTArenaAlloc<48> alloc;
 
     *dst = src;   // catch case where there are no loops
-    SkDrawLooper::Context* context = this->makeContext(&canvas, &alloc);
+    SkDrawLooper::Context* context = this->makeContext(&alloc);
 
     for (bool firstTime = true;; firstTime = false) {
         SkPaint p(paint);
-        if (context->next(&canvas, &p)) {
+        SkDrawLooper::Context::Info info;
+        if (context->next(&info, &p)) {
             SkRect r(src);
 
 #ifdef SK_SUPPORT_LEGACY_DRAWLOOPER
             p.setLooper(nullptr);
 #endif
             p.computeFastBounds(r, &r);
-            canvas.getTotalMatrix().mapRect(&r);
+            r.offset(info.fTranslate.fX, info.fTranslate.fY);
 
             if (firstTime) {
                 *dst = r;
@@ -73,14 +91,24 @@
 void SkDrawLooper::apply(SkCanvas* canvas, const SkPaint& paint,
                          std::function<void(SkCanvas*, const SkPaint&)> proc) {
     SkSTArenaAlloc<256> alloc;
-    Context* ctx = this->makeContext(canvas, &alloc);
+    Context* ctx = this->makeContext(&alloc);
     if (ctx) {
+        Context::Info info;
         for (;;) {
             SkPaint p = paint;
-            if (!ctx->next(canvas, &p)) {
+            if (!ctx->next(&info, &p)) {
                 break;
             }
+            canvas->save();
+            if (info.fApplyPostCTM) {
+                SkMatrix ctm = canvas->getTotalMatrix();
+                ctm.postTranslate(info.fTranslate.fX, info.fTranslate.fY);
+                canvas->setMatrix(ctm);
+            } else {
+                canvas->translate(info.fTranslate.fX, info.fTranslate.fY);
+            }
             proc(canvas, p);
+            canvas->restore();
         }
     }
 }
diff --git a/src/effects/SkLayerDrawLooper.cpp b/src/effects/SkLayerDrawLooper.cpp
index 1dd5b29..4259221 100644
--- a/src/effects/SkLayerDrawLooper.cpp
+++ b/src/effects/SkLayerDrawLooper.cpp
@@ -42,8 +42,7 @@
 }
 
 SkLayerDrawLooper::Context*
-SkLayerDrawLooper::makeContext(SkCanvas* canvas, SkArenaAlloc* alloc) const {
-    canvas->save();
+SkLayerDrawLooper::makeContext(SkArenaAlloc* alloc) const {
     return alloc->make<LayerDrawLooperContext>(this);
 }
 
@@ -130,35 +129,21 @@
 #endif
 }
 
-// Should we add this to canvas?
-static void postTranslate(SkCanvas* canvas, SkScalar dx, SkScalar dy) {
-    SkMatrix m = canvas->getTotalMatrix();
-    m.postTranslate(dx, dy);
-    canvas->setMatrix(m);
-}
-
 SkLayerDrawLooper::LayerDrawLooperContext::LayerDrawLooperContext(
         const SkLayerDrawLooper* looper) : fCurrRec(looper->fRecs) {}
 
-bool SkLayerDrawLooper::LayerDrawLooperContext::next(SkCanvas* canvas,
-                                                     SkPaint* paint) {
-    canvas->restore();
+bool SkLayerDrawLooper::LayerDrawLooperContext::next(Info* info, SkPaint* paint) {
     if (nullptr == fCurrRec) {
         return false;
     }
 
     ApplyInfo(paint, fCurrRec->fPaint, fCurrRec->fInfo);
 
-    canvas->save();
-    if (fCurrRec->fInfo.fPostTranslate) {
-        postTranslate(canvas, fCurrRec->fInfo.fOffset.fX,
-                      fCurrRec->fInfo.fOffset.fY);
-    } else {
-        canvas->translate(fCurrRec->fInfo.fOffset.fX,
-                          fCurrRec->fInfo.fOffset.fY);
+    if (info) {
+        info->fTranslate = fCurrRec->fInfo.fOffset;
+        info->fApplyPostCTM = fCurrRec->fInfo.fPostTranslate;
     }
     fCurrRec = fCurrRec->fNext;
-
     return true;
 }