Flags for render_pictures: verify, clone and writeWholeImage:
1) flag to verify PNGs produced by render_picture that produce the same pixels
as simple renderer.
2) flag to write one single image (in tile we write individual tiles) - this
will help running skdiff also
3) flag to clone the picture before rendering

git-svn-id: http://skia.googlecode.com/svn/trunk@6890 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/tools/PictureRenderer.cpp b/tools/PictureRenderer.cpp
index ab87274..61de8c6 100644
--- a/tools/PictureRenderer.cpp
+++ b/tools/PictureRenderer.cpp
@@ -243,7 +243,7 @@
     return SkImageEncoder::EncodeStream(wStream, bm, SkImageEncoder::kPNG_Type, 100);
 }
 
-bool RecordPictureRenderer::render(const SkString* path) {
+bool RecordPictureRenderer::render(const SkString* path, SkBitmap** out) {
     SkAutoTUnref<SkPicture> replayer(this->createPicture());
     SkCanvas* recorder = replayer->beginRecording(this->getViewWidth(), this->getViewHeight(),
                                                   this->recordFlags());
@@ -268,7 +268,7 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
-bool PipePictureRenderer::render(const SkString* path) {
+bool PipePictureRenderer::render(const SkString* path, SkBitmap** out) {
     SkASSERT(fCanvas.get() != NULL);
     SkASSERT(fPicture != NULL);
     if (NULL == fCanvas.get() || NULL == fPicture) {
@@ -284,6 +284,11 @@
     if (NULL != path) {
         return write(fCanvas, *path);
     }
+    if (NULL != out) {
+        *out = SkNEW(SkBitmap);
+        setup_bitmap(*out, fPicture->width(), fPicture->height());
+        fCanvas->readPixels(*out, 0, 0);
+    }    
     return true;
 }
 
@@ -298,7 +303,7 @@
     this->buildBBoxHierarchy();
 }
 
-bool SimplePictureRenderer::render(const SkString* path) {
+bool SimplePictureRenderer::render(const SkString* path, SkBitmap** out) {
     SkASSERT(fCanvas.get() != NULL);
     SkASSERT(fPicture != NULL);
     if (NULL == fCanvas.get() || NULL == fPicture) {
@@ -310,6 +315,13 @@
     if (NULL != path) {
         return write(fCanvas, *path);
     }
+    
+    if (NULL != out) {
+        *out = SkNEW(SkBitmap);
+        setup_bitmap(*out, fPicture->width(), fPicture->height());
+        fCanvas->readPixels(*out, 0, 0);
+    }
+
     return true;
 }
 
@@ -467,6 +479,15 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
+static void bitmapCopySubset(const SkBitmap& src, SkBitmap* dst, int xDst,
+                             int yDst) {
+    for (int y = 0; y <src.height() && y + yDst < dst->height() ; y++) {
+        for (int x = 0; x < src.width() && x + xDst < dst->width() ; x++) {
+            *dst->getAddr32(xDst + x, yDst + y) = *src.getAddr32(x, y);
+        }
+    }
+}
+
 bool TiledPictureRenderer::nextTile(int &i, int &j) {
     if (++fCurrentTileOffset < fTileRects.count()) {
         i = fCurrentTileOffset % fTilesX;
@@ -481,18 +502,32 @@
     DrawTileToCanvas(fCanvas, fTileRects[fCurrentTileOffset], fPicture);
 }
 
-bool TiledPictureRenderer::render(const SkString* path) {
+bool TiledPictureRenderer::render(const SkString* path, SkBitmap** out) {
     SkASSERT(fPicture != NULL);
     if (NULL == fPicture) {
         return false;
     }
 
+    SkBitmap bitmap;
+    if (out){
+        *out = SkNEW(SkBitmap);
+        setup_bitmap(*out, fPicture->width(), fPicture->height());
+        setup_bitmap(&bitmap, fTileWidth, fTileHeight);
+    }
     bool success = true;
     for (int i = 0; i < fTileRects.count(); ++i) {
         DrawTileToCanvas(fCanvas, fTileRects[i], fPicture);
         if (NULL != path) {
             success &= writeAppendNumber(fCanvas, path, i);
         }
+        if (NULL != out) {
+            if (fCanvas->readPixels(&bitmap, 0, 0)) {
+                bitmapCopySubset(bitmap, *out, fTileRects[i].left(),
+                                 fTileRects[i].top());
+            } else {
+                success = false;
+            }
+        }
     }
     return success;
 }
@@ -555,6 +590,13 @@
 
     virtual void run() SK_OVERRIDE {
         SkGraphics::SetTLSFontCacheLimit(1024 * 1024);
+
+        SkBitmap bitmap;
+        if (fBitmap != NULL) {
+            // All tiles are the same size.
+            setup_bitmap(&bitmap, fRects[0].width(), fRects[0].height());
+        }
+        
         for (int i = fStart; i < fEnd; i++) {
             DrawTileToCanvas(fCanvas, fRects[i], fClone);
             if (fPath != NULL && !writeAppendNumber(fCanvas, fPath, i)
@@ -563,6 +605,17 @@
                 // If one tile fails to write to a file, do not continue drawing the rest.
                 break;
             }
+            if (fBitmap != NULL) {
+                if (fCanvas->readPixels(&bitmap, 0, 0)) {
+                    SkAutoLockPixels alp(*fBitmap);
+                    bitmapCopySubset(bitmap, fBitmap, fRects[i].left(),
+                                     fRects[i].top());
+                } else {
+                    *fSuccess = false;
+                    // If one tile fails to read pixels, do not continue drawing the rest.
+                    break;
+                }
+            }
         }
         fDone->run();
     }
@@ -572,6 +625,10 @@
         fSuccess = success;
     }
 
+    void setBitmap(SkBitmap* bitmap) {
+        fBitmap = bitmap;
+    }
+
 private:
     // All pointers unowned.
     SkPicture*         fClone;      // Picture to draw from. Each CloneData has a unique one which
@@ -584,6 +641,7 @@
     bool*              fSuccess;    // Only meaningful if path is non-null. Shared by all threads,
                                     // and only set to false upon failure to write to a PNG.
     SkRunnable*        fDone;
+    SkBitmap*          fBitmap;
 };
 
 MultiCorePictureRenderer::MultiCorePictureRenderer(int threadCount)
@@ -623,7 +681,7 @@
     }
 }
 
-bool MultiCorePictureRenderer::render(const SkString *path) {
+bool MultiCorePictureRenderer::render(const SkString *path, SkBitmap** out) {
     bool success = true;
     if (path != NULL) {
         for (int i = 0; i < fNumThreads-1; i++) {
@@ -631,6 +689,18 @@
         }
     }
 
+    if (NULL != out) {
+        *out = SkNEW(SkBitmap);
+        setup_bitmap(*out, fPicture->width(), fPicture->height());
+        for (int i = 0; i < fNumThreads; i++) {
+            fCloneData[i]->setBitmap(*out);
+        }
+    } else {
+        for (int i = 0; i < fNumThreads; i++) {
+            fCloneData[i]->setBitmap(NULL);
+        }
+    }
+
     fCountdown.reset(fNumThreads);
     for (int i = 0; i < fNumThreads; i++) {
         fThreadPool.add(fCloneData[i]);
@@ -673,7 +743,7 @@
     fPicture->draw(recorder);
 }
 
-bool PlaybackCreationRenderer::render(const SkString*) {
+bool PlaybackCreationRenderer::render(const SkString*, SkBitmap** out) {
     fReplayer->endRecording();
     // Since this class does not actually render, return false.
     return false;
@@ -716,7 +786,8 @@
 
 class GatherRenderer : public PictureRenderer {
 public:
-    virtual bool render(const SkString* path) SK_OVERRIDE {
+    virtual bool render(const SkString* path, SkBitmap** out = NULL)
+            SK_OVERRIDE {
         SkRect bounds = SkRect::MakeWH(SkIntToScalar(fPicture->width()),
                                        SkIntToScalar(fPicture->height()));
         SkData* data = SkPictureUtils::GatherPixelRefs(fPicture, bounds);
@@ -739,7 +810,8 @@
 
 class PictureCloneRenderer : public PictureRenderer {
 public:
-    virtual bool render(const SkString* path) SK_OVERRIDE {
+    virtual bool render(const SkString* path, SkBitmap** out = NULL)
+            SK_OVERRIDE {
         for (int i = 0; i < 100; ++i) {
             SkPicture* clone = fPicture->clone();
             SkSafeUnref(clone);