Changed to a class based method in passing around the rendering method for render_pictures.

This is based on a comment for https://codereview.appspot.com/6427061/

Review URL: https://codereview.appspot.com/6405080

git-svn-id: http://skia.googlecode.com/svn/trunk@4786 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gyp/tools.gyp b/gyp/tools.gyp
index 47ab49a..2ab422f 100644
--- a/gyp/tools.gyp
+++ b/gyp/tools.gyp
@@ -70,8 +70,6 @@
       'type': 'executable',
       'sources': [
         '../tools/render_pictures_main.cpp',
-        '../src/pipe/utils/SamplePipeControllers.h',
-        '../src/pipe/utils/SamplePipeControllers.cpp',
       ],
       'include_dirs': [
         '../src/pipe/utils/',
@@ -80,6 +78,7 @@
         'core.gyp:core',
         'images.gyp:images',
         'ports.gyp:ports',
+        'tools.gyp:PictureRenderer',
         'tools.gyp:picture_utils',
       ],
     },
@@ -104,6 +103,22 @@
       ],
     },
     {
+     'target_name': 'PictureRenderer',
+     'type': 'static_library',
+     'sources': [
+        '../tools/PictureRenderer.cpp',
+        '../src/pipe/utils/SamplePipeControllers.h',
+        '../src/pipe/utils/SamplePipeControllers.cpp',
+     ],
+      'include_dirs': [
+        '../src/pipe/utils/',
+      ],
+     'dependencies': [
+        'core.gyp:core',
+        'tools.gyp:picture_utils',
+     ],
+    },
+    {
       'target_name': 'picture_utils',
       'type': 'static_library',
       'sources': [
diff --git a/tools/PictureRenderer.cpp b/tools/PictureRenderer.cpp
new file mode 100644
index 0000000..762b49c
--- /dev/null
+++ b/tools/PictureRenderer.cpp
@@ -0,0 +1,101 @@
+#include "PictureRenderer.h"
+#include "SamplePipeControllers.h"
+#include "SkCanvas.h"
+#include "SkDevice.h"
+#include "SkGPipe.h"
+#include "SkPicture.h"
+#include "SkTDArray.h"
+#include "SkTypes.h"
+#include "picture_utils.h"
+
+namespace sk_tools {
+
+enum {
+    kDefaultTileWidth = 256,
+    kDefaultTileHeight = 256
+};
+
+void PipePictureRenderer::render(SkPicture* pict, SkCanvas* canvas) {
+    PipeController pipeController(canvas);
+    SkGPipeWriter writer;
+    SkCanvas* pipeCanvas = writer.startRecording(&pipeController);
+    pipeCanvas->drawPicture(*pict);
+    writer.endRecording();
+}
+
+void SimplePictureRenderer::render(SkPicture* pict, SkCanvas* canvas) {
+    canvas->drawPicture(*pict);
+}
+
+TiledPictureRenderer::TiledPictureRenderer()
+    : fTileWidth(kDefaultTileWidth)
+    , fTileHeight(kDefaultTileHeight) {}
+
+void TiledPictureRenderer::init(const SkPicture& pict) {
+    deleteTiles();
+    setupTiles(pict);
+}
+
+void TiledPictureRenderer::render(SkPicture* pict, SkCanvas* canvas) {
+    for (int i = 0; i < fTiles.count(); ++i) {
+        fTiles[i].fCanvas->drawPicture(*pict);
+    }
+
+    copyTilesToCanvas(*pict, canvas);
+}
+
+TiledPictureRenderer::~TiledPictureRenderer() {
+    deleteTiles();
+}
+
+void TiledPictureRenderer::clipTile(const SkPicture& picture, const TileInfo& tile) {
+    SkRect clip = SkRect::MakeWH(SkIntToScalar(picture.width()),
+                                 SkIntToScalar(picture.height()));
+    tile.fCanvas->clipRect(clip);
+}
+
+void TiledPictureRenderer::addTile(const SkPicture& picture, int tile_x_start, int tile_y_start) {
+    TileInfo* tile = fTiles.push();
+
+    tile->fBitmap = SkNEW(SkBitmap);
+    sk_tools::setup_bitmap(tile->fBitmap, fTileWidth, fTileHeight);
+
+    tile->fCanvas = SkNEW_ARGS(SkCanvas, (*(tile->fBitmap)));
+    tile->fCanvas->translate(SkIntToScalar(-tile_x_start), SkIntToScalar(-tile_y_start));
+    clipTile(picture, *tile);
+}
+
+void TiledPictureRenderer::setupTiles(const SkPicture& picture) {
+    for (int tile_y_start = 0; tile_y_start < picture.height();
+         tile_y_start += fTileHeight) {
+        for (int tile_x_start = 0; tile_x_start < picture.width();
+             tile_x_start += fTileWidth) {
+            addTile(picture, tile_x_start, tile_y_start);
+        }
+    }
+}
+
+void TiledPictureRenderer::deleteTiles() {
+    for (int i = 0; i < fTiles.count(); ++i) {
+        SkDELETE(fTiles[i].fCanvas);
+        SkDELETE(fTiles[i].fBitmap);
+    }
+
+    fTiles.reset();
+}
+
+void TiledPictureRenderer::copyTilesToCanvas(const SkPicture& pict, SkCanvas* destination) {
+    int tile_index = 0;
+    for (int tile_y_start = 0; tile_y_start < pict.height();
+         tile_y_start += fTileHeight) {
+        for (int tile_x_start = 0; tile_x_start < pict.width();
+             tile_x_start += fTileWidth) {
+            SkASSERT(tile_index < fTiles.count());
+            SkBitmap source = fTiles[tile_index].fCanvas->getDevice()->accessBitmap(false);
+            destination->drawBitmap(source, tile_x_start, tile_y_start);
+            ++tile_index;
+        }
+    }
+}
+
+}
diff --git a/tools/PictureRenderer.h b/tools/PictureRenderer.h
new file mode 100644
index 0000000..5fa53c1
--- /dev/null
+++ b/tools/PictureRenderer.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef PictureRenderer_DEFINED
+#define PictureRenderer_DEFINED
+#include "SkTypes.h"
+#include "SkTDArray.h"
+#include "SkRefCnt.h"
+
+class SkBitmap;
+class SkCanvas;
+class SkPicture;
+
+namespace sk_tools {
+
+class PictureRenderer : public SkRefCnt {
+public:
+    virtual void init(const SkPicture& pict){}
+    virtual void render(SkPicture* pict, SkCanvas* canvas) = 0;
+};
+
+class PipePictureRenderer : public PictureRenderer {
+    virtual void render(SkPicture* pict, SkCanvas* canvas);
+};
+
+class SimplePictureRenderer : public PictureRenderer {
+    virtual void render (SkPicture* pict, SkCanvas* canvas);
+};
+
+class TiledPictureRenderer : public PictureRenderer {
+public:
+    TiledPictureRenderer();
+
+    virtual void init(const SkPicture& pict);
+    virtual void render(SkPicture* pict, SkCanvas* canvas);
+
+    ~TiledPictureRenderer();
+
+private:
+    struct TileInfo {
+        SkBitmap* fBitmap;
+        SkCanvas* fCanvas;
+    };
+
+    int fTileWidth;
+    int fTileHeight;
+
+    SkTDArray<TileInfo> fTiles;
+
+    // Clips the tile to an area that is completely in what the SkPicture says is the
+    // drawn-to area. This is mostly important for tiles on the right and bottom edges
+    // as they may go over this area and the picture may have some commands that
+    // draw outside of this area and so should not actually be written.
+    static void clipTile(const SkPicture& picture, const TileInfo& tile);
+    void addTile(const SkPicture& picture, int tile_x_start, int tile_y_start);
+    void setupTiles(const SkPicture& picture);
+    // We manually delete the tiles instead of having a destructor on TileInfo as
+    // the destructor on TileInfo will be during a realloc. This would result in
+    // the canvases and bitmaps being prematurely deleted.
+    void deleteTiles();
+    void copyTilesToCanvas(const SkPicture& pict, SkCanvas* destination);
+};
+
+}
+
+#endif  // PictureRenderer_DEFINED
diff --git a/tools/render_pictures_main.cpp b/tools/render_pictures_main.cpp
index 5572b28..8c22756 100644
--- a/tools/render_pictures_main.cpp
+++ b/tools/render_pictures_main.cpp
@@ -5,27 +5,19 @@
  * found in the LICENSE file.
  */
 
-
 #include "SkBitmap.h"
-#include "SamplePipeControllers.h"
 #include "SkCanvas.h"
 #include "SkColorPriv.h"
 #include "SkDevice.h"
-#include "SkGPipe.h"
 #include "SkImageEncoder.h"
 #include "SkOSFile.h"
 #include "SkPicture.h"
 #include "SkStream.h"
 #include "SkString.h"
 #include "SkTArray.h"
-#include "SkTDArray.h"
+#include "PictureRenderer.h"
 #include "picture_utils.h"
 
-enum {
-    kDefaultTileWidth = 256,
-    kDefaultTileHeight = 256
-};
-
 static void usage(const char* argv0) {
     SkDebugf("SkPicture rendering tool\n");
     SkDebugf("\n"
@@ -45,9 +37,6 @@
 "     --tile : Render using tiles.\n");
 }
 
-static void simple_render(SkPicture* pict, SkBitmap* bitmap);
-typedef void (*RenderFunc) (SkPicture*, SkBitmap*);
-
 static void make_output_filepath(SkString* path, const SkString& dir,
                                  const SkString& name) {
     sk_tools::make_filepath(path, dir, name);
@@ -55,12 +44,6 @@
     path->append("png");
 }
 
-static void simple_render(SkPicture* pict, SkBitmap* bitmap) {
-    sk_tools::setup_bitmap(bitmap, pict->width(), pict->height());
-    SkCanvas canvas(*bitmap);
-    canvas.drawPicture(*pict);
-}
-
 /* since PNG insists on unpremultiplying our alpha, we take no precision chances
     and force all pixels to be 100% opaque, otherwise on compare we may not get
     a perfect match.
@@ -92,94 +75,8 @@
     }
 }
 
-static void pipe_run(SkPicture* picture, SkCanvas* canvas) {
-    PipeController pipeController(canvas);
-    SkGPipeWriter writer;
-    SkCanvas* pipeCanvas = writer.startRecording(&pipeController);
-    pipeCanvas->drawPicture(*picture);
-    writer.endRecording();
-}
-
-static void pipe_render(SkPicture* picture, SkBitmap* bitmap) {
-    sk_tools::setup_bitmap(bitmap, picture->width(), picture->height());
-
-    SkCanvas canvas(*bitmap);
-
-    pipe_run(picture, &canvas);
-}
-
-struct TileInfo {
-    SkBitmap* fBitmap;
-    SkCanvas* fCanvas;
-};
-
-// Clips the tile to an area that is completely in what the SkPicture says is the
-// drawn-to area. This is mostly important for tiles on the right and bottom edges
-// as they may go over this area and the picture may have some commands that
-// draw outside of this area and so should not actually be written.
-static void clip_tile(SkPicture* picture, const TileInfo& tile) {
-    SkRect clip = SkRect::MakeWH(SkIntToScalar(picture->width()),
-                                 SkIntToScalar(picture->height()));
-    tile.fCanvas->clipRect(clip);
-}
-
-static void add_tile(SkPicture* picture, SkTDArray<TileInfo>* tiles,
-                     int tile_x_start, int tile_y_start) {
-    TileInfo* tile = tiles->push();
-
-    tile->fBitmap = new SkBitmap();
-    sk_tools::setup_bitmap(tile->fBitmap, kDefaultTileWidth, kDefaultTileHeight);
-
-    tile->fCanvas = new SkCanvas(*(tile->fBitmap));
-    tile->fCanvas->translate(SkIntToScalar(-tile_x_start), SkIntToScalar(-tile_y_start));
-    clip_tile(picture, *tile);
-}
-
-static void setup_tiles(SkPicture* picture, SkTDArray<TileInfo>* tiles) {
-    for (int tile_y_start = 0; tile_y_start < picture->height();
-         tile_y_start += kDefaultTileWidth) {
-        for (int tile_x_start = 0; tile_x_start < picture->width();
-             tile_x_start += kDefaultTileHeight) {
-            add_tile(picture, tiles, tile_x_start, tile_y_start);
-        }
-    }
-}
-
-static void copy_tiles_to_bitmap(const SkTDArray<TileInfo>& tiles, SkBitmap* bitmap) {
-    SkCanvas destination(*bitmap);
-
-    int tile_index = 0;
-    for (int tile_y_start = 0; tile_y_start < bitmap->height();
-         tile_y_start += kDefaultTileWidth) {
-        for (int tile_x_start = 0; tile_x_start < bitmap->width();
-             tile_x_start += kDefaultTileHeight) {
-            SkBitmap source = tiles[tile_index].fCanvas->getDevice()->accessBitmap(false);
-            destination.drawBitmap(source, tile_x_start, tile_y_start);
-            ++tile_index;
-        }
-    }
-}
-
-static void tile_render(SkPicture* picture, SkBitmap* bitmap) {
-    sk_tools::setup_bitmap(bitmap, picture->width(), picture->height());
-
-    SkTDArray<TileInfo> tiles;
-    setup_tiles(picture, &tiles);
-
-    for (int i = 0; i < tiles.count(); ++i) {
-        tiles[i].fCanvas->drawPicture(*picture);
-    }
-
-    copy_tiles_to_bitmap(tiles, bitmap);
-
-    for (int i = 0; i < tiles.count(); ++i) {
-        delete tiles[i].fCanvas;
-        delete tiles[i].fBitmap;
-    }
-}
-
 static void render_picture(const SkString& inputPath, const SkString& outputDir,
-                           RenderFunc renderFunc) {
+                           sk_tools::PictureRenderer& renderer) {
     SkString inputFilename;
     sk_tools::get_basename(&inputFilename, inputPath);
 
@@ -192,12 +89,16 @@
 
     SkPicture picture(&inputStream);
     SkBitmap bitmap;
-    renderFunc(&picture, &bitmap);
+    sk_tools::setup_bitmap(&bitmap, picture.width(), picture.height());
+    SkCanvas canvas(bitmap);
+
+    renderer.init(picture);
+    renderer.render(&picture, &canvas);
     write_output(outputDir, inputFilename, bitmap);
 }
 
 static void process_input(const SkString& input, const SkString& outputDir,
-                          RenderFunc renderFunc) {
+                          sk_tools::PictureRenderer& renderer) {
     SkOSFile::Iter iter(input.c_str(), "skp");
     SkString inputFilename;
 
@@ -205,25 +106,26 @@
         do {
             SkString inputPath;
             sk_tools::make_filepath(&inputPath, input, inputFilename);
-            render_picture(inputPath, outputDir, renderFunc);
+            render_picture(inputPath, outputDir, renderer);
         } while(iter.next(&inputFilename));
     } else {
         SkString inputPath(input);
-        render_picture(inputPath, outputDir, renderFunc);
+        render_picture(inputPath, outputDir, renderer);
     }
 }
 
 static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>* inputs,
-                              RenderFunc* renderFunc){
+                              sk_tools::PictureRenderer*& renderer){
     const char* argv0 = argv[0];
     char* const* stop = argv + argc;
 
     for (++argv; argv < stop; ++argv) {
         if (0 == strcmp(*argv, "--pipe")) {
-            *renderFunc = pipe_render;
+            renderer = SkNEW(sk_tools::PipePictureRenderer);
         } else if (0 == strcmp(*argv, "--tile")) {
-            *renderFunc = tile_render;
+            renderer = SkNEW(sk_tools::TiledPictureRenderer);
         } else if ((0 == strcmp(*argv, "-h")) || (0 == strcmp(*argv, "--help"))) {
+            SkDELETE(renderer);
             usage(argv0);
             exit(-1);
         } else {
@@ -232,19 +134,27 @@
     }
 
     if (inputs->count() < 2) {
+        SkDELETE(renderer);
         usage(argv0);
         exit(-1);
     }
+
+    if (NULL == renderer) {
+        renderer = SkNEW(sk_tools::SimplePictureRenderer);
+    }
 }
 
 int main(int argc, char* const argv[]) {
     SkTArray<SkString> inputs;
-    RenderFunc renderFunc = simple_render;
+    sk_tools::PictureRenderer* renderer = NULL;
 
-    parse_commandline(argc, argv, &inputs, &renderFunc);
+    parse_commandline(argc, argv, &inputs, renderer);
     SkString outputDir = inputs[inputs.count() - 1];
+    SkASSERT(renderer);
 
     for (int i = 0; i < inputs.count() - 1; i ++) {
-        process_input(inputs[i], outputDir, renderFunc);
+        process_input(inputs[i], outputDir, *renderer);
     }
+
+    SkDELETE(renderer);
 }