DM: add draw_to_canvas() to trim some boilerplate for Vias.

BUG=skia:

Review URL: https://codereview.chromium.org/1123743007
diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp
index b33ba14..c5e0395 100644
--- a/dm/DMSrcSink.cpp
+++ b/dm/DMSrcSink.cpp
@@ -7,8 +7,8 @@
 
 #include "DMSrcSink.h"
 #include "SamplePipeControllers.h"
-#include "SkCommonFlags.h"
 #include "SkCodec.h"
+#include "SkCommonFlags.h"
 #include "SkData.h"
 #include "SkDeferredCanvas.h"
 #include "SkDocument.h"
@@ -20,8 +20,8 @@
 #include "SkPictureData.h"
 #include "SkPictureRecorder.h"
 #include "SkRandom.h"
-#include "SkScanlineDecoder.h"
 #include "SkSVGCanvas.h"
+#include "SkScanlineDecoder.h"
 #include "SkStream.h"
 #include "SkXMLWriter.h"
 
@@ -502,6 +502,28 @@
 
 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
+// Handy for front-patching a Src.  Do whatever up-front work you need, then call draw_to_canvas(),
+// passing the Sink draw() arguments, a size, and a lambda that takes SkCanvas* and returns Error.
+// Several examples below.
+
+template <typename DrawFn>
+static Error draw_to_canvas(Sink* sink, SkBitmap* bitmap, SkWStream* stream, SkString* log,
+                            SkISize size, DrawFn draw) {
+    class ProxySrc : public Src {
+    public:
+        ProxySrc(SkISize size, DrawFn draw) : fSize(size), fDraw(draw) {}
+        Error   draw(SkCanvas* canvas) const override { return fDraw(canvas); }
+        Name                    name() const override { sk_throw(); return ""; } // Won't be called.
+        SkISize                 size() const override { return fSize; }
+    private:
+        SkISize fSize;
+        DrawFn  fDraw;
+    };
+    return sink->draw(ProxySrc(size, draw), bitmap, stream, log);
+}
+
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
 static SkISize auto_compute_translate(SkMatrix* matrix, int srcW, int srcH) {
     SkRect bounds = SkRect::MakeIWH(srcW, srcH);
     matrix->mapRect(&bounds);
@@ -512,24 +534,12 @@
 ViaMatrix::ViaMatrix(SkMatrix matrix, Sink* sink) : fMatrix(matrix), fSink(sink) {}
 
 Error ViaMatrix::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
-    // We turn our arguments into a Src, then draw that Src into our Sink to fill bitmap or stream.
-    struct ProxySrc : public Src {
-        const Src&  fSrc;
-        SkMatrix    fMatrix;
-        SkISize     fSize;
-
-        ProxySrc(const Src& src, SkMatrix matrix) : fSrc(src), fMatrix(matrix) {
-            fSize = auto_compute_translate(&fMatrix, src.size().width(), src.size().height());
-        }
-
-        Error draw(SkCanvas* canvas) const override {
-            canvas->concat(fMatrix);
-            return fSrc.draw(canvas);
-        }
-        SkISize size() const override { return fSize; }
-        Name name() const override { sk_throw(); return ""; }  // No one should be calling this.
-    } proxy(src, fMatrix);
-    return fSink->draw(proxy, bitmap, stream, log);
+    SkMatrix matrix = fMatrix;
+    SkISize size = auto_compute_translate(&matrix, src.size().width(), src.size().height());
+    return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) {
+        canvas->concat(matrix);
+        return src.draw(canvas);
+    });
 }
 
 // Undoes any flip or 90 degree rotate without changing the scale of the bitmap.
@@ -572,70 +582,52 @@
 ViaPipe::ViaPipe(Sink* sink) : fSink(sink) {}
 
 Error ViaPipe::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
-    // We turn ourselves into another Src that draws our argument into bitmap/stream via pipe.
-    struct ProxySrc : public Src {
-        const Src& fSrc;
-        ProxySrc(const Src& src) : fSrc(src) {}
-
-        Error draw(SkCanvas* canvas) const override {
-            SkISize size = this->size();
-            PipeController controller(canvas, &SkImageDecoder::DecodeMemory);
-            SkGPipeWriter pipe;
-            const uint32_t kFlags = 0; // We mirror SkDeferredCanvas, which doesn't use any flags.
-            return fSrc.draw(pipe.startRecording(&controller, kFlags, size.width(), size.height()));
-        }
-        SkISize size() const override { return fSrc.size(); }
-        Name name() const override { sk_throw(); return ""; }  // No one should be calling this.
-    } proxy(src);
-    return fSink->draw(proxy, bitmap, stream, log);
+    auto size = src.size();
+    return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) {
+        PipeController controller(canvas, &SkImageDecoder::DecodeMemory);
+        SkGPipeWriter pipe;
+        const uint32_t kFlags = 0; // We mirror SkDeferredCanvas, which doesn't use any flags.
+        return src.draw(pipe.startRecording(&controller, kFlags, size.width(), size.height()));
+    });
 }
 
 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-    
+
 ViaDeferred::ViaDeferred(Sink* sink) : fSink(sink) {}
 
 Error ViaDeferred::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
-    // We turn ourselves into another Src that draws our argument into a deferred canvas,
-    // via a surface created by the original canvas. We then draw a snapped image from that
-    // surface back into the original canvas.
-    struct ProxySrc : public Src {
-        const Src& fSrc;
-        ProxySrc(const Src& src) : fSrc(src) {}
-
-        Error draw(SkCanvas* canvas) const override {
-            SkAutoTUnref<SkSurface> surface(canvas->newSurface(canvas->imageInfo()));
-            if (!surface.get()) {
-                return "can't make surface for deferred canvas";
-            }
-            SkAutoTDelete<SkDeferredCanvas> defcan(SkDeferredCanvas::Create(surface));
-            Error err = fSrc.draw(defcan);
-            if (!err.isEmpty()) {
-                return err;
-            }
-            SkAutoTUnref<SkImage> image(defcan->newImageSnapshot());
-            if (!image) {
-                return "failed to create deferred image snapshot";
-            }
-            canvas->drawImage(image, 0, 0, NULL);
-            return "";
+    // We draw via a deferred canvas into a surface that's compatible with the original canvas,
+    // then snap that surface as an image and draw it into the original canvas.
+    return draw_to_canvas(fSink, bitmap, stream, log, src.size(), [&](SkCanvas* canvas) -> Error {
+        SkAutoTUnref<SkSurface> surface(canvas->newSurface(canvas->imageInfo()));
+        if (!surface.get()) {
+            return "can't make surface for deferred canvas";
         }
-        SkISize size() const override { return fSrc.size(); }
-        Name name() const override { sk_throw(); return ""; }  // No one should be calling this.
-    } proxy(src);
-    return fSink->draw(proxy, bitmap, stream, log);
+        SkAutoTDelete<SkDeferredCanvas> defcan(SkDeferredCanvas::Create(surface));
+        Error err = src.draw(defcan);
+        if (!err.isEmpty()) {
+            return err;
+        }
+        SkAutoTUnref<SkImage> image(defcan->newImageSnapshot());
+        if (!image) {
+            return "failed to create deferred image snapshot";
+        }
+        canvas->drawImage(image, 0, 0, NULL);
+        return "";
+    });
 }
-    
+
 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
 ViaSerialization::ViaSerialization(Sink* sink) : fSink(sink) {}
 
-Error ViaSerialization::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log)
-    const {
+Error ViaSerialization::draw(
+        const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
     // Record our Src into a picture.
-    SkSize size;
-    size = src.size();
+    auto size = src.size();
     SkPictureRecorder recorder;
-    Error err = src.draw(recorder.beginRecording(size.width(), size.height()));
+    Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
+                                                 SkIntToScalar(size.height())));
     if (!err.isEmpty()) {
         return err;
     }
@@ -647,20 +639,10 @@
     SkAutoTDelete<SkStream> rStream(wStream.detachAsStream());
     SkAutoTUnref<SkPicture> deserialized(SkPicture::CreateFromStream(rStream, &lazy_decode_bitmap));
 
-    // Turn that deserialized picture into a Src, draw it into our Sink to fill bitmap or stream.
-    struct ProxySrc : public Src {
-        const SkPicture* fPic;
-        const SkISize fSize;
-        ProxySrc(const SkPicture* pic, SkISize size) : fPic(pic), fSize(size) {}
-
-        Error draw(SkCanvas* canvas) const override {
-            canvas->drawPicture(fPic);
-            return "";
-        }
-        SkISize size() const override { return fSize; }
-        Name name() const override { sk_throw(); return ""; }  // No one should be calling this.
-    } proxy(deserialized, src.size());
-    return fSink->draw(proxy, bitmap, stream, log);
+    return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) {
+        canvas->drawPicture(deserialized);
+        return "";
+    });
 }
 
 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
@@ -672,61 +654,49 @@
     , fSink(sink) {}
 
 Error ViaTiles::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
-    // Record our Src into a picture.
-    SkSize size;
-    size = src.size();
+    auto size = src.size();
     SkPictureRecorder recorder;
-    Error err = src.draw(recorder.beginRecording(size.width(), size.height(), fFactory.get()));
+    Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
+                                                 SkIntToScalar(size.height()),
+                                                 fFactory.get()));
     if (!err.isEmpty()) {
         return err;
     }
     SkAutoTUnref<SkPicture> pic(recorder.endRecordingAsPicture());
 
-    // Turn that picture into a Src that draws into our Sink via tiles + MPD.
-    struct ProxySrc : public Src {
-        const int fW, fH;
-        const SkPicture* fPic;
-        const SkISize fSize;
-        ProxySrc(int w, int h, const SkPicture* pic, SkISize size)
-            : fW(w), fH(h), fPic(pic), fSize(size) {}
+    return draw_to_canvas(fSink, bitmap, stream, log, src.size(), [&](SkCanvas* canvas) {
+        const int xTiles = (size.width()  + fW - 1) / fW,
+                  yTiles = (size.height() + fH - 1) / fH;
+        SkMultiPictureDraw mpd(xTiles*yTiles);
+        SkTDArray<SkSurface*> surfaces;
+        surfaces.setReserve(xTiles*yTiles);
 
-        Error draw(SkCanvas* canvas) const override {
-            const int xTiles = (fSize.width()  + fW - 1) / fW,
-                      yTiles = (fSize.height() + fH - 1) / fH;
-            SkMultiPictureDraw mpd(xTiles*yTiles);
-            SkTDArray<SkSurface*> surfaces;
-            surfaces.setReserve(xTiles*yTiles);
-
-            SkImageInfo info = canvas->imageInfo().makeWH(fW, fH);
-            for (int j = 0; j < yTiles; j++) {
-                for (int i = 0; i < xTiles; i++) {
-                    // This lets our ultimate Sink determine the best kind of surface.
-                    // E.g., if it's a GpuSink, the surfaces and images are textures.
-                    SkSurface* s = canvas->newSurface(info);
-                    if (!s) {
-                        s = SkSurface::NewRaster(info);  // Some canvases can't create surfaces.
-                    }
-                    surfaces.push(s);
-                    SkCanvas* c = s->getCanvas();
-                    c->translate(SkIntToScalar(-i * fW),
-                                 SkIntToScalar(-j * fH));  // Line up the canvas with this tile.
-                    mpd.add(c, fPic);
+        SkImageInfo info = canvas->imageInfo().makeWH(fW, fH);
+        for (int j = 0; j < yTiles; j++) {
+            for (int i = 0; i < xTiles; i++) {
+                // This lets our ultimate Sink determine the best kind of surface.
+                // E.g., if it's a GpuSink, the surfaces and images are textures.
+                SkSurface* s = canvas->newSurface(info);
+                if (!s) {
+                    s = SkSurface::NewRaster(info);  // Some canvases can't create surfaces.
                 }
+                surfaces.push(s);
+                SkCanvas* c = s->getCanvas();
+                c->translate(SkIntToScalar(-i * fW),
+                             SkIntToScalar(-j * fH));  // Line up the canvas with this tile.
+                mpd.add(c, pic);
             }
-            mpd.draw();
-            for (int j = 0; j < yTiles; j++) {
-                for (int i = 0; i < xTiles; i++) {
-                    SkAutoTUnref<SkImage> image(surfaces[i+xTiles*j]->newImageSnapshot());
-                    canvas->drawImage(image, SkIntToScalar(i*fW), SkIntToScalar(j*fH));
-                }
-            }
-            surfaces.unrefAll();
-            return "";
         }
-        SkISize size() const override { return fSize; }
-        Name name() const override { sk_throw(); return ""; }  // No one should be calling this.
-    } proxy(fW, fH, pic, src.size());
-    return fSink->draw(proxy, bitmap, stream, log);
+        mpd.draw();
+        for (int j = 0; j < yTiles; j++) {
+            for (int i = 0; i < xTiles; i++) {
+                SkAutoTUnref<SkImage> image(surfaces[i+xTiles*j]->newImageSnapshot());
+                canvas->drawImage(image, SkIntToScalar(i*fW), SkIntToScalar(j*fH));
+            }
+        }
+        surfaces.unrefAll();
+        return "";
+    });
 }
 
 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
@@ -737,29 +707,21 @@
 // This tests that any shortcuts we may take while recording that second picture are legal.
 Error ViaSecondPicture::draw(
         const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
-    struct ProxySrc : public Src {
-        const Src& fSrc;
-        ProxySrc(const Src& src) : fSrc(src) {}
-
-        Error draw(SkCanvas* canvas) const override {
-            SkSize size;
-            size = fSrc.size();
-            SkPictureRecorder recorder;
-            SkAutoTUnref<SkPicture> pic;
-            for (int i = 0; i < 2; i++) {
-                Error err = fSrc.draw(recorder.beginRecording(size.width(), size.height()));
-                if (!err.isEmpty()) {
-                    return err;
-                }
-                pic.reset(recorder.endRecordingAsPicture());
+    auto size = src.size();
+    return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
+        SkPictureRecorder recorder;
+        SkAutoTUnref<SkPicture> pic;
+        for (int i = 0; i < 2; i++) {
+            Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
+                                                         SkIntToScalar(size.height())));
+            if (!err.isEmpty()) {
+                return err;
             }
-            canvas->drawPicture(pic);
-            return "";
+            pic.reset(recorder.endRecordingAsPicture());
         }
-        SkISize size() const override { return fSrc.size(); }
-        Name name() const override { sk_throw(); return ""; }  // No one should be calling this.
-    } proxy(src);
-    return fSink->draw(proxy, bitmap, stream, log);
+        canvas->drawPicture(pic);
+        return "";
+    });
 }
 
 }  // namespace DM