Allow bench_pictures to have its viewport set on the command line.

Instead of drawing the entire (potentially very large) picture, only
draw one viewport's worth.

example:

bench_pictures <skp directory> --viewport 640 480

BUG=https://code.google.com/p/skia/issues/detail?id=1007

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

git-svn-id: http://skia.googlecode.com/svn/trunk@6799 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/tools/CopyTilesRenderer.cpp b/tools/CopyTilesRenderer.cpp
index 553209c..0df43bb 100644
--- a/tools/CopyTilesRenderer.cpp
+++ b/tools/CopyTilesRenderer.cpp
@@ -38,8 +38,8 @@
         int i = 0;
         bool success = true;
         SkBitmap dst;
-        for (int x = 0; x < fPicture->width(); x += fLargeTileWidth) {
-            for (int y = 0; y < fPicture->height(); y += fLargeTileHeight) {
+        for (int x = 0; x < this->getViewWidth(); x += fLargeTileWidth) {
+            for (int y = 0; y < this->getViewHeight(); y += fLargeTileHeight) {
                 SkAutoCanvasRestore autoRestore(fCanvas, true);
                 fCanvas->translate(SkIntToScalar(-x), SkIntToScalar(-y));
                 // Draw the picture
diff --git a/tools/PictureRenderer.cpp b/tools/PictureRenderer.cpp
index 034e8fc..ac5e47c 100644
--- a/tools/PictureRenderer.cpp
+++ b/tools/PictureRenderer.cpp
@@ -98,7 +98,9 @@
 }
 
 SkCanvas* PictureRenderer::setupCanvas() {
-    return this->setupCanvas(fPicture->width(), fPicture->height());
+    const int width = this->getViewWidth();
+    const int height = this->getViewHeight();
+    return this->setupCanvas(width, height);
 }
 
 SkCanvas* PictureRenderer::setupCanvas(int width, int height) {
@@ -133,6 +135,24 @@
     fCanvas.reset(NULL);
 }
 
+int PictureRenderer::getViewWidth() {
+    SkASSERT(fPicture != NULL);
+    int width = fPicture->width();
+    if (fViewport.width() > 0) {
+        width = SkMin32(width, fViewport.width());
+    }
+    return width;
+}
+
+int PictureRenderer::getViewHeight() {
+    SkASSERT(fPicture != NULL);
+    int height = fPicture->height();
+    if (fViewport.height() > 0) {
+        height = SkMin32(height, fViewport.height());
+    }
+    return height;
+}
+
 /** Converts fPicture to a picture that uses a BBoxHierarchy.
  *  PictureRenderer subclasses that are used to test picture playback
  *  should call this method during init.
@@ -336,8 +356,12 @@
 }
 
 void TiledPictureRenderer::setupTiles() {
-    for (int tile_y_start = 0; tile_y_start < fPicture->height(); tile_y_start += fTileHeight) {
-        for (int tile_x_start = 0; tile_x_start < fPicture->width(); tile_x_start += fTileWidth) {
+    // Only use enough tiles to cover the viewport
+    const int width = this->getViewWidth();
+    const int height = this->getViewHeight();
+
+    for (int tile_y_start = 0; tile_y_start < height; tile_y_start += fTileHeight) {
+        for (int tile_x_start = 0; tile_x_start < width; tile_x_start += fTileWidth) {
             *fTileRects.append() = SkRect::MakeXYWH(SkIntToScalar(tile_x_start),
                                                     SkIntToScalar(tile_y_start),
                                                     SkIntToScalar(fTileWidth),
@@ -356,17 +380,20 @@
 // value gives us the tiles we need: a bit of value one means we need a tile of
 // that size.
 void TiledPictureRenderer::setupPowerOf2Tiles() {
-    int rounded_value = fPicture->width();
-    if (fPicture->width() % fTileMinPowerOf2Width != 0) {
-        rounded_value = fPicture->width() - (fPicture->width() % fTileMinPowerOf2Width)
-            + fTileMinPowerOf2Width;
+    // Only use enough tiles to cover the viewport
+    const int width = this->getViewWidth();
+    const int height = this->getViewHeight();
+
+    int rounded_value = width;
+    if (width % fTileMinPowerOf2Width != 0) {
+        rounded_value = width - (width % fTileMinPowerOf2Width) + fTileMinPowerOf2Width;
     }
 
-    int num_bits = SkScalarCeilToInt(SkScalarLog2(SkIntToScalar(fPicture->width())));
+    int num_bits = SkScalarCeilToInt(SkScalarLog2(SkIntToScalar(width)));
     int largest_possible_tile_size = 1 << num_bits;
 
     // The tile height is constant for a particular picture.
-    for (int tile_y_start = 0; tile_y_start < fPicture->height(); tile_y_start += fTileHeight) {
+    for (int tile_y_start = 0; tile_y_start < height; tile_y_start += fTileHeight) {
         int tile_x_start = 0;
         int current_width = largest_possible_tile_size;
         // Set fTileWidth to be the width of the widest tile, so that each canvas is large enough
@@ -429,12 +456,13 @@
 SkCanvas* TiledPictureRenderer::setupCanvas(int width, int height) {
     SkCanvas* canvas = this->INHERITED::setupCanvas(width, height);
     SkASSERT(fPicture != NULL);
+    const int totalWidth = this->getViewWidth();
+    const int totalHeight = this->getViewHeight();
     // Clip 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.
-    SkRect clip = SkRect::MakeWH(SkIntToScalar(fPicture->width()),
-                                 SkIntToScalar(fPicture->height()));
+    SkRect clip = SkRect::MakeWH(SkIntToScalar(totalWidth), SkIntToScalar(totalHeight));
     canvas->clipRect(clip);
     return canvas;
 }
diff --git a/tools/PictureRenderer.h b/tools/PictureRenderer.h
index 192569c..eda89a0 100644
--- a/tools/PictureRenderer.h
+++ b/tools/PictureRenderer.h
@@ -70,6 +70,11 @@
     virtual void init(SkPicture* pict);
 
     /**
+     *  Set the viewport so that only the portion listed gets drawn.
+     */
+    void setViewport(SkISize size) { fViewport = size; }
+
+    /**
      * Perform any setup that should done prior to each iteration of render() which should not be
      * timed.
      */
@@ -168,29 +173,45 @@
 #endif
         {
             sk_bzero(fDrawFilters, sizeof(fDrawFilters));
+            fViewport.set(0, 0);
         }
 
 protected:
-    void buildBBoxHierarchy();
-    SkPicture* createPicture();
-    uint32_t recordFlags();
-    SkCanvas* setupCanvas();
-    virtual SkCanvas* setupCanvas(int width, int height);
-
     SkAutoTUnref<SkCanvas> fCanvas;
-    SkPicture* fPicture;
-    SkDeviceTypes fDeviceType;
-    BBoxHierarchyType fBBoxHierarchyType;
-    DrawFilterFlags fDrawFilters[SkDrawFilter::kTypeCount];
-    SkString fDrawFiltersConfig;
-    int fGridWidth, fGridHeight; // used when fBBoxHierarchyType is TileGrid
+    SkPicture*             fPicture;
+    SkDeviceTypes          fDeviceType;
+    BBoxHierarchyType      fBBoxHierarchyType;
+    DrawFilterFlags        fDrawFilters[SkDrawFilter::kTypeCount];
+    SkString               fDrawFiltersConfig;
+    int                    fGridWidth, fGridHeight; // used when fBBoxHierarchyType is TileGrid
 
 #if SK_SUPPORT_GPU
     GrContextFactory fGrContextFactory;
     GrContext* fGrContext;
 #endif
 
+    void buildBBoxHierarchy();
+
+    /**
+     * Return the total width that should be drawn. If the viewport width has been set greater than
+     * 0, this will be the minimum of the current SkPicture's width and the viewport's width.
+     */
+    int getViewWidth();
+
+    /**
+     * Return the total height that should be drawn. If the viewport height has been set greater
+     * than 0, this will be the minimum of the current SkPicture's height and the viewport's height.
+     */
+    int getViewHeight();
+
+    SkPicture* createPicture();
+    uint32_t recordFlags();
+    SkCanvas* setupCanvas();
+    virtual SkCanvas* setupCanvas(int width, int height);
+
 private:
+    SkISize                fViewport;
+
     virtual SkString getConfigNameInternal() = 0;
 
     typedef SkRefCnt INHERITED;
diff --git a/tools/bench_pictures_main.cpp b/tools/bench_pictures_main.cpp
index 47844f9..ca63807 100644
--- a/tools/bench_pictures_main.cpp
+++ b/tools/bench_pictures_main.cpp
@@ -126,6 +126,7 @@
 "     [--pipe]\n"
 "     [--bbh bbhType]\n"
 "     [--multi numThreads]\n"
+"     [--viewport width height]\n"
 "     [--device bitmap"
 #if SK_SUPPORT_GPU
 " | gpu"
@@ -179,6 +180,7 @@
     SkDebugf(
 "     --multi numThreads : Set the number of threads for multi threaded drawing. Must be greater\n"
 "                          than 1. Only works with tiled rendering.\n"
+"     --viewport width height : Set the viewport.\n"
 "     --pipe: Benchmark SkGPipe rendering. Currently incompatible with \"mode\".\n");
     SkDebugf(
 "     --bbh bbhType [width height]: Set the bounding box hierarchy type to\n"
@@ -289,6 +291,8 @@
         sk_tools::PictureRenderer::kNone_BBoxHierarchyType;
     sk_tools::PictureRenderer::DrawFilterFlags drawFilters[SkDrawFilter::kTypeCount];
     sk_bzero(drawFilters, sizeof(drawFilters));
+    SkISize viewport;
+    viewport.setEmpty();
     for (++argv; argv < stop; ++argv) {
         if (0 == strcmp(*argv, "--repeat")) {
             ++argv;
@@ -423,6 +427,19 @@
                 gLogger.logError(err);
                 PRINT_USAGE_AND_EXIT;
             }
+        } else if (0 == strcmp(*argv, "--viewport")) {
+            ++argv;
+            if (argv >= stop) {
+                gLogger.logError("Missing width for --viewport\n");
+                PRINT_USAGE_AND_EXIT;
+            }
+            viewport.fWidth = atoi(*argv);
+            ++argv;
+            if (argv >= stop) {
+                gLogger.logError("Missing height for --viewport\n");
+                PRINT_USAGE_AND_EXIT;
+            }
+            viewport.fHeight = atoi(*argv);
         } else if (0 == strcmp(*argv, "--tiles")) {
             ++argv;
             if (argv >= stop) {
@@ -697,6 +714,7 @@
     renderer->setBBoxHierarchyType(bbhType);
     renderer->setDrawFilters(drawFilters, filtersName(drawFilters));
     renderer->setGridSize(gridWidth, gridHeight);
+    renderer->setViewport(viewport);
     benchmark->setRenderer(renderer);
     benchmark->setRepeats(repeats);
     benchmark->setDeviceType(deviceType);
diff --git a/tools/render_pictures_main.cpp b/tools/render_pictures_main.cpp
index 250058e..d43e1c4 100644
--- a/tools/render_pictures_main.cpp
+++ b/tools/render_pictures_main.cpp
@@ -30,6 +30,7 @@
 "         | tile width height]\n"
 "     [--pipe]\n"
 "     [--multi count]\n"
+"     [--viewport width height]\n"
 "     [--device bitmap"
 #if SK_SUPPORT_GPU
 " | gpu"
@@ -74,6 +75,7 @@
     SkDebugf(
 "     --multi count : Set the number of threads for multi threaded drawing. Must be greater\n"
 "                     than 1. Only works with tiled rendering.\n"
+"     --viewport width height : Set the viewport.\n"
 "     --pipe: Benchmark SkGPipe rendering. Currently incompatible with \"mode\".\n");
     SkDebugf(
 "     --device bitmap"
@@ -185,7 +187,8 @@
     const char* xTilesString = NULL;
     const char* yTilesString = NULL;
     const char* mode = NULL;
-
+    SkISize viewport;
+    viewport.setEmpty();
     for (++argv; argv < stop; ++argv) {
         if (0 == strcmp(*argv, "--mode")) {
             if (renderer != NULL) {
@@ -237,6 +240,21 @@
                 usage(argv0);
                 exit(-1);
             }
+        } else if (0 == strcmp(*argv, "--viewport")) {
+            ++argv;
+            if (argv >= stop) {
+                SkDebugf("Missing width for --viewport\n");
+                usage(argv0);
+                exit(-1);
+            }
+            viewport.fWidth = atoi(*argv);
+            ++argv;
+            if (argv >= stop) {
+                SkDebugf("Missing height for --viewport\n");
+                usage(argv0);
+                exit(-1);
+            }
+            viewport.fHeight = atoi(*argv);
         } else if (0 == strcmp(*argv, "--tiles")) {
             ++argv;
             if (argv >= stop) {
@@ -441,6 +459,7 @@
         renderer = SkNEW(sk_tools::SimplePictureRenderer);
     }
 
+    renderer->setViewport(viewport);
     renderer->setDeviceType(deviceType);
 }