Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / tools / PictureRenderer.cpp
1 /*
2  * Copyright 2012 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7
8 #include "PictureRenderer.h"
9 #include "picture_utils.h"
10 #include "SamplePipeControllers.h"
11 #include "SkBitmapHasher.h"
12 #include "SkCanvas.h"
13 #include "SkData.h"
14 #include "SkDevice.h"
15 #include "SkDiscardableMemoryPool.h"
16 #include "SkGPipe.h"
17 #if SK_SUPPORT_GPU
18 #include "gl/GrGLDefines.h"
19 #include "SkGpuDevice.h"
20 #endif
21 #include "SkGraphics.h"
22 #include "SkImageEncoder.h"
23 #include "SkMaskFilter.h"
24 #include "SkMatrix.h"
25 #include "SkOSFile.h"
26 #include "SkPicture.h"
27 #include "SkPictureRecorder.h"
28 #include "SkPictureUtils.h"
29 #include "SkPixelRef.h"
30 #include "SkScalar.h"
31 #include "SkStream.h"
32 #include "SkString.h"
33 #include "SkTemplates.h"
34 #include "SkTDArray.h"
35 #include "SkThreadUtils.h"
36 #include "SkTypes.h"
37
38 static inline SkScalar scalar_log2(SkScalar x) {
39     static const SkScalar log2_conversion_factor = SkScalarDiv(1, SkScalarLog(2));
40
41     return SkScalarLog(x) * log2_conversion_factor;
42 }
43
44 namespace sk_tools {
45
46 enum {
47     kDefaultTileWidth = 256,
48     kDefaultTileHeight = 256
49 };
50
51 void PictureRenderer::init(const SkPicture* pict,
52                            const SkString* writePath,
53                            const SkString* mismatchPath,
54                            const SkString* inputFilename,
55                            bool useChecksumBasedFilenames) {
56     this->CopyString(&fWritePath, writePath);
57     this->CopyString(&fMismatchPath, mismatchPath);
58     this->CopyString(&fInputFilename, inputFilename);
59     fUseChecksumBasedFilenames = useChecksumBasedFilenames;
60
61     SkASSERT(NULL == fPicture);
62     SkASSERT(NULL == fCanvas.get());
63     if (fPicture || fCanvas.get()) {
64         return;
65     }
66
67     SkASSERT(pict != NULL);
68     if (NULL == pict) {
69         return;
70     }
71
72     fPicture.reset(pict)->ref();
73     fCanvas.reset(this->setupCanvas());
74 }
75
76 void PictureRenderer::CopyString(SkString* dest, const SkString* src) {
77     if (src) {
78         dest->set(*src);
79     } else {
80         dest->reset();
81     }
82 }
83
84 class FlagsDrawFilter : public SkDrawFilter {
85 public:
86     FlagsDrawFilter(PictureRenderer::DrawFilterFlags* flags) :
87         fFlags(flags) {}
88
89     virtual bool filter(SkPaint* paint, Type t) {
90         paint->setFlags(paint->getFlags() & ~fFlags[t] & SkPaint::kAllFlags);
91         if (PictureRenderer::kMaskFilter_DrawFilterFlag & fFlags[t]) {
92             SkMaskFilter* maskFilter = paint->getMaskFilter();
93             if (maskFilter) {
94                 paint->setMaskFilter(NULL);
95             }
96         }
97         if (PictureRenderer::kHinting_DrawFilterFlag & fFlags[t]) {
98             paint->setHinting(SkPaint::kNo_Hinting);
99         } else if (PictureRenderer::kSlightHinting_DrawFilterFlag & fFlags[t]) {
100             paint->setHinting(SkPaint::kSlight_Hinting);
101         }
102         return true;
103     }
104
105 private:
106     PictureRenderer::DrawFilterFlags* fFlags;
107 };
108
109 static void setUpFilter(SkCanvas* canvas, PictureRenderer::DrawFilterFlags* drawFilters) {
110     if (drawFilters && !canvas->getDrawFilter()) {
111         canvas->setDrawFilter(SkNEW_ARGS(FlagsDrawFilter, (drawFilters)))->unref();
112         if (drawFilters[0] & PictureRenderer::kAAClip_DrawFilterFlag) {
113             canvas->setAllowSoftClip(false);
114         }
115     }
116 }
117
118 SkCanvas* PictureRenderer::setupCanvas() {
119     const int width = this->getViewWidth();
120     const int height = this->getViewHeight();
121     return this->setupCanvas(width, height);
122 }
123
124 SkCanvas* PictureRenderer::setupCanvas(int width, int height) {
125     SkCanvas* canvas;
126     switch(fDeviceType) {
127         case kBitmap_DeviceType: {
128             SkBitmap bitmap;
129             sk_tools::setup_bitmap(&bitmap, width, height);
130             canvas = SkNEW_ARGS(SkCanvas, (bitmap));
131         }
132         break;
133 #if SK_SUPPORT_GPU
134 #if SK_ANGLE
135         case kAngle_DeviceType:
136             // fall through
137 #endif
138 #if SK_MESA
139         case kMesa_DeviceType:
140             // fall through
141 #endif
142         case kGPU_DeviceType:
143         case kNVPR_DeviceType: {
144             SkAutoTUnref<GrSurface> target;
145             if (fGrContext) {
146                 // create a render target to back the device
147                 GrTextureDesc desc;
148                 desc.fConfig = kSkia8888_GrPixelConfig;
149                 desc.fFlags = kRenderTarget_GrTextureFlagBit;
150                 desc.fWidth = width;
151                 desc.fHeight = height;
152                 desc.fSampleCnt = fSampleCount;
153                 target.reset(fGrContext->createUncachedTexture(desc, NULL, 0));
154             }
155             if (NULL == target.get()) {
156                 SkASSERT(0);
157                 return NULL;
158             }
159
160             SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(target,
161                                          SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType)));
162             canvas = SkNEW_ARGS(SkCanvas, (device.get()));
163             break;
164         }
165 #endif
166         default:
167             SkASSERT(0);
168             return NULL;
169     }
170     setUpFilter(canvas, fDrawFilters);
171     this->scaleToScaleFactor(canvas);
172
173     // Pictures often lie about their extent (i.e., claim to be 100x100 but
174     // only ever draw to 90x100). Clear here so the undrawn portion will have
175     // a consistent color
176     canvas->clear(SK_ColorTRANSPARENT);
177     return canvas;
178 }
179
180 void PictureRenderer::scaleToScaleFactor(SkCanvas* canvas) {
181     SkASSERT(canvas != NULL);
182     if (fScaleFactor != SK_Scalar1) {
183         canvas->scale(fScaleFactor, fScaleFactor);
184     }
185 }
186
187 void PictureRenderer::end() {
188     this->resetState(true);
189     fPicture.reset(NULL);
190     fCanvas.reset(NULL);
191 }
192
193 int PictureRenderer::getViewWidth() {
194     SkASSERT(fPicture != NULL);
195     int width = SkScalarCeilToInt(fPicture->cullRect().width() * fScaleFactor);
196     if (fViewport.width() > 0) {
197         width = SkMin32(width, fViewport.width());
198     }
199     return width;
200 }
201
202 int PictureRenderer::getViewHeight() {
203     SkASSERT(fPicture != NULL);
204     int height = SkScalarCeilToInt(fPicture->cullRect().height() * fScaleFactor);
205     if (fViewport.height() > 0) {
206         height = SkMin32(height, fViewport.height());
207     }
208     return height;
209 }
210
211 /** Converts fPicture to a picture that uses a BBoxHierarchy.
212  *  PictureRenderer subclasses that are used to test picture playback
213  *  should call this method during init.
214  */
215 void PictureRenderer::buildBBoxHierarchy() {
216     SkASSERT(fPicture);
217     if (kNone_BBoxHierarchyType != fBBoxHierarchyType && fPicture) {
218         SkAutoTDelete<SkBBHFactory> factory(this->getFactory());
219         SkPictureRecorder recorder;
220         SkCanvas* canvas = recorder.beginRecording(fPicture->cullRect().width(), 
221                                                    fPicture->cullRect().height(),
222                                                    factory.get(),
223                                                    this->recordFlags());
224         fPicture->playback(canvas);
225         fPicture.reset(recorder.endRecording());
226     }
227 }
228
229 void PictureRenderer::resetState(bool callFinish) {
230 #if SK_SUPPORT_GPU
231     SkGLContextHelper* glContext = this->getGLContext();
232     if (NULL == glContext) {
233         SkASSERT(kBitmap_DeviceType == fDeviceType);
234         return;
235     }
236
237     fGrContext->flush();
238     glContext->swapBuffers();
239     if (callFinish) {
240         SK_GL(*glContext, Finish());
241     }
242 #endif
243 }
244
245 void PictureRenderer::purgeTextures() {
246     SkDiscardableMemoryPool* pool = SkGetGlobalDiscardableMemoryPool();
247
248     pool->dumpPool();
249
250 #if SK_SUPPORT_GPU
251     SkGLContextHelper* glContext = this->getGLContext();
252     if (NULL == glContext) {
253         SkASSERT(kBitmap_DeviceType == fDeviceType);
254         return;
255     }
256
257     // resetState should've already done this
258     fGrContext->flush();
259
260     fGrContext->purgeAllUnlockedResources();
261 #endif
262 }
263
264 /**
265  * Write the canvas to an image file and/or JSON summary.
266  *
267  * @param canvas Must be non-null. Canvas to be written to a file.
268  * @param writePath If nonempty, write the binary image to a file within this directory.
269  * @param mismatchPath If nonempty, write the binary image to a file within this directory,
270  *     but only if the image does not match expectations.
271  * @param inputFilename If we are writing out a binary image, use this to build its filename.
272  * @param jsonSummaryPtr If not null, add image results (checksum) to this summary.
273  * @param useChecksumBasedFilenames If true, use checksum-based filenames when writing to disk.
274  * @param tileNumberPtr If not null, which tile number this image contains.
275  *
276  * @return bool True if the operation completed successfully.
277  */
278 static bool write(SkCanvas* canvas, const SkString& writePath, const SkString& mismatchPath,
279                   const SkString& inputFilename, ImageResultsAndExpectations *jsonSummaryPtr,
280                   bool useChecksumBasedFilenames, const int* tileNumberPtr=NULL) {
281     SkASSERT(canvas != NULL);
282     if (NULL == canvas) {
283         return false;
284     }
285
286     SkBitmap bitmap;
287     SkISize size = canvas->getDeviceSize();
288     setup_bitmap(&bitmap, size.width(), size.height());
289
290     canvas->readPixels(&bitmap, 0, 0);
291     force_all_opaque(bitmap);
292     BitmapAndDigest bitmapAndDigest(bitmap);
293
294     SkString escapedInputFilename(inputFilename);
295     replace_char(&escapedInputFilename, '.', '_');
296
297     // TODO(epoger): what about including the config type within outputFilename?  That way,
298     // we could combine results of different config types without conflicting filenames.
299     SkString outputFilename;
300     const char *outputSubdirPtr = NULL;
301     if (useChecksumBasedFilenames) {
302         ImageDigest *imageDigestPtr = bitmapAndDigest.getImageDigestPtr();
303         outputSubdirPtr = escapedInputFilename.c_str();
304         outputFilename.set(imageDigestPtr->getHashType());
305         outputFilename.append("_");
306         outputFilename.appendU64(imageDigestPtr->getHashValue());
307     } else {
308         outputFilename.set(escapedInputFilename);
309         if (tileNumberPtr) {
310             outputFilename.append("-tile");
311             outputFilename.appendS32(*tileNumberPtr);
312         }
313     }
314     outputFilename.append(".png");
315
316     if (jsonSummaryPtr) {
317         ImageDigest *imageDigestPtr = bitmapAndDigest.getImageDigestPtr();
318         SkString outputRelativePath;
319         if (outputSubdirPtr) {
320             outputRelativePath.set(outputSubdirPtr);
321             outputRelativePath.append("/");  // always use "/", even on Windows
322             outputRelativePath.append(outputFilename);
323         } else {
324             outputRelativePath.set(outputFilename);
325         }
326
327         jsonSummaryPtr->add(inputFilename.c_str(), outputRelativePath.c_str(),
328                             *imageDigestPtr, tileNumberPtr);
329         if (!mismatchPath.isEmpty() &&
330             !jsonSummaryPtr->getExpectation(inputFilename.c_str(),
331                                             tileNumberPtr).matches(*imageDigestPtr)) {
332             if (!write_bitmap_to_disk(bitmap, mismatchPath, outputSubdirPtr, outputFilename)) {
333                 return false;
334             }
335         }
336     }
337
338     if (writePath.isEmpty()) {
339         return true;
340     } else {
341         return write_bitmap_to_disk(bitmap, writePath, outputSubdirPtr, outputFilename);
342     }
343 }
344
345 ///////////////////////////////////////////////////////////////////////////////////////////////
346
347 SkCanvas* RecordPictureRenderer::setupCanvas(int width, int height) {
348     // defer the canvas setup until the render step
349     return NULL;
350 }
351
352 // the size_t* parameter is deprecated, so we ignore it
353 static SkData* encode_bitmap_to_data(size_t*, const SkBitmap& bm) {
354     return SkImageEncoder::EncodeData(bm, SkImageEncoder::kPNG_Type, 100);
355 }
356
357 bool RecordPictureRenderer::render(SkBitmap** out) {
358     SkAutoTDelete<SkBBHFactory> factory(this->getFactory());
359     SkPictureRecorder recorder;
360     SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(this->getViewWidth()), 
361                                                SkIntToScalar(this->getViewHeight()),
362                                                factory.get(),
363                                                this->recordFlags());
364     this->scaleToScaleFactor(canvas);
365     fPicture->playback(canvas);
366     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
367     if (!fWritePath.isEmpty()) {
368         // Record the new picture as a new SKP with PNG encoded bitmaps.
369         SkString skpPath = SkOSPath::Join(fWritePath.c_str(), fInputFilename.c_str());
370         SkFILEWStream stream(skpPath.c_str());
371         picture->serialize(&stream, &encode_bitmap_to_data);
372         return true;
373     }
374     return false;
375 }
376
377 SkString RecordPictureRenderer::getConfigNameInternal() {
378     return SkString("record");
379 }
380
381 ///////////////////////////////////////////////////////////////////////////////////////////////
382
383 bool PipePictureRenderer::render(SkBitmap** out) {
384     SkASSERT(fCanvas.get() != NULL);
385     SkASSERT(fPicture != NULL);
386     if (NULL == fCanvas.get() || NULL == fPicture) {
387         return false;
388     }
389
390     PipeController pipeController(fCanvas.get());
391     SkGPipeWriter writer;
392     SkCanvas* pipeCanvas = writer.startRecording(&pipeController);
393     pipeCanvas->drawPicture(fPicture);
394     writer.endRecording();
395     fCanvas->flush();
396     if (out) {
397         *out = SkNEW(SkBitmap);
398         setup_bitmap(*out, SkScalarCeilToInt(fPicture->cullRect().width()), 
399                            SkScalarCeilToInt(fPicture->cullRect().height()));
400         fCanvas->readPixels(*out, 0, 0);
401     }
402     if (fEnableWrites) {
403         return write(fCanvas, fWritePath, fMismatchPath, fInputFilename, fJsonSummaryPtr,
404                      fUseChecksumBasedFilenames);
405     } else {
406         return true;
407     }
408 }
409
410 SkString PipePictureRenderer::getConfigNameInternal() {
411     return SkString("pipe");
412 }
413
414 ///////////////////////////////////////////////////////////////////////////////////////////////
415
416 void SimplePictureRenderer::init(const SkPicture* picture, const SkString* writePath,
417                                  const SkString* mismatchPath, const SkString* inputFilename,
418                                  bool useChecksumBasedFilenames) {
419     INHERITED::init(picture, writePath, mismatchPath, inputFilename, useChecksumBasedFilenames);
420     this->buildBBoxHierarchy();
421 }
422
423 bool SimplePictureRenderer::render(SkBitmap** out) {
424     SkASSERT(fCanvas.get() != NULL);
425     SkASSERT(fPicture);
426     if (NULL == fCanvas.get() || NULL == fPicture) {
427         return false;
428     }
429
430     fCanvas->drawPicture(fPicture);
431     fCanvas->flush();
432     if (out) {
433         *out = SkNEW(SkBitmap);
434         setup_bitmap(*out, SkScalarCeilToInt(fPicture->cullRect().width()), 
435                            SkScalarCeilToInt(fPicture->cullRect().height()));
436         fCanvas->readPixels(*out, 0, 0);
437     }
438     if (fEnableWrites) {
439         return write(fCanvas, fWritePath, fMismatchPath, fInputFilename, fJsonSummaryPtr,
440                      fUseChecksumBasedFilenames);
441     } else {
442         return true;
443     }
444 }
445
446 SkString SimplePictureRenderer::getConfigNameInternal() {
447     return SkString("simple");
448 }
449
450 ///////////////////////////////////////////////////////////////////////////////////////////////
451
452 #if SK_SUPPORT_GPU
453 TiledPictureRenderer::TiledPictureRenderer(const GrContext::Options& opts)
454     : INHERITED(opts)
455     , fTileWidth(kDefaultTileWidth)
456 #else
457 TiledPictureRenderer::TiledPictureRenderer()
458     : fTileWidth(kDefaultTileWidth)
459 #endif
460     , fTileHeight(kDefaultTileHeight)
461     , fTileWidthPercentage(0.0)
462     , fTileHeightPercentage(0.0)
463     , fTileMinPowerOf2Width(0)
464     , fCurrentTileOffset(-1)
465     , fTilesX(0)
466     , fTilesY(0) { }
467
468 void TiledPictureRenderer::init(const SkPicture* pict, const SkString* writePath,
469                                 const SkString* mismatchPath, const SkString* inputFilename,
470                                 bool useChecksumBasedFilenames) {
471     SkASSERT(pict);
472     SkASSERT(0 == fTileRects.count());
473     if (NULL == pict || fTileRects.count() != 0) {
474         return;
475     }
476
477     // Do not call INHERITED::init(), which would create a (potentially large) canvas which is not
478     // used by bench_pictures.
479     fPicture.reset(pict)->ref();
480     this->CopyString(&fWritePath, writePath);
481     this->CopyString(&fMismatchPath, mismatchPath);
482     this->CopyString(&fInputFilename, inputFilename);
483     fUseChecksumBasedFilenames = useChecksumBasedFilenames;
484     this->buildBBoxHierarchy();
485
486     if (fTileWidthPercentage > 0) {
487         fTileWidth = SkScalarCeilToInt(float(fTileWidthPercentage * fPicture->cullRect().width() / 100));
488     }
489     if (fTileHeightPercentage > 0) {
490         fTileHeight = SkScalarCeilToInt(float(fTileHeightPercentage * fPicture->cullRect().height() / 100));
491     }
492
493     if (fTileMinPowerOf2Width > 0) {
494         this->setupPowerOf2Tiles();
495     } else {
496         this->setupTiles();
497     }
498     fCanvas.reset(this->setupCanvas(fTileWidth, fTileHeight));
499     // Initialize to -1 so that the first call to nextTile will set this up to draw tile 0 on the
500     // first call to drawCurrentTile.
501     fCurrentTileOffset = -1;
502 }
503
504 void TiledPictureRenderer::end() {
505     fTileRects.reset();
506     this->INHERITED::end();
507 }
508
509 void TiledPictureRenderer::setupTiles() {
510     // Only use enough tiles to cover the viewport
511     const int width = this->getViewWidth();
512     const int height = this->getViewHeight();
513
514     fTilesX = fTilesY = 0;
515     for (int tile_y_start = 0; tile_y_start < height; tile_y_start += fTileHeight) {
516         fTilesY++;
517         for (int tile_x_start = 0; tile_x_start < width; tile_x_start += fTileWidth) {
518             if (0 == tile_y_start) {
519                 // Only count tiles in the X direction on the first pass.
520                 fTilesX++;
521             }
522             *fTileRects.append() = SkRect::MakeXYWH(SkIntToScalar(tile_x_start),
523                                                     SkIntToScalar(tile_y_start),
524                                                     SkIntToScalar(fTileWidth),
525                                                     SkIntToScalar(fTileHeight));
526         }
527     }
528 }
529
530 bool TiledPictureRenderer::tileDimensions(int &x, int &y) {
531     if (fTileRects.count() == 0 || NULL == fPicture) {
532         return false;
533     }
534     x = fTilesX;
535     y = fTilesY;
536     return true;
537 }
538
539 // The goal of the powers of two tiles is to minimize the amount of wasted tile
540 // space in the width-wise direction and then minimize the number of tiles. The
541 // constraints are that every tile must have a pixel width that is a power of
542 // two and also be of some minimal width (that is also a power of two).
543 //
544 // This is solved by first taking our picture size and rounding it up to the
545 // multiple of the minimal width. The binary representation of this rounded
546 // value gives us the tiles we need: a bit of value one means we need a tile of
547 // that size.
548 void TiledPictureRenderer::setupPowerOf2Tiles() {
549     // Only use enough tiles to cover the viewport
550     const int width = this->getViewWidth();
551     const int height = this->getViewHeight();
552
553     int rounded_value = width;
554     if (width % fTileMinPowerOf2Width != 0) {
555         rounded_value = width - (width % fTileMinPowerOf2Width) + fTileMinPowerOf2Width;
556     }
557
558     int num_bits = SkScalarCeilToInt(scalar_log2(SkIntToScalar(width)));
559     int largest_possible_tile_size = 1 << num_bits;
560
561     fTilesX = fTilesY = 0;
562     // The tile height is constant for a particular picture.
563     for (int tile_y_start = 0; tile_y_start < height; tile_y_start += fTileHeight) {
564         fTilesY++;
565         int tile_x_start = 0;
566         int current_width = largest_possible_tile_size;
567         // Set fTileWidth to be the width of the widest tile, so that each canvas is large enough
568         // to draw each tile.
569         fTileWidth = current_width;
570
571         while (current_width >= fTileMinPowerOf2Width) {
572             // It is very important this is a bitwise AND.
573             if (current_width & rounded_value) {
574                 if (0 == tile_y_start) {
575                     // Only count tiles in the X direction on the first pass.
576                     fTilesX++;
577                 }
578                 *fTileRects.append() = SkRect::MakeXYWH(SkIntToScalar(tile_x_start),
579                                                         SkIntToScalar(tile_y_start),
580                                                         SkIntToScalar(current_width),
581                                                         SkIntToScalar(fTileHeight));
582                 tile_x_start += current_width;
583             }
584
585             current_width >>= 1;
586         }
587     }
588 }
589
590 /**
591  * Draw the specified picture to the canvas translated to rectangle provided, so that this mini
592  * canvas represents the rectangle's portion of the overall picture.
593  * Saves and restores so that the initial clip and matrix return to their state before this function
594  * is called.
595  */
596 static void draw_tile_to_canvas(SkCanvas* canvas,
597                                 const SkRect& tileRect,
598                                 const SkPicture* picture) {
599     int saveCount = canvas->save();
600     // Translate so that we draw the correct portion of the picture.
601     // Perform a postTranslate so that the scaleFactor does not interfere with the positioning.
602     SkMatrix mat(canvas->getTotalMatrix());
603     mat.postTranslate(-tileRect.fLeft, -tileRect.fTop);
604     canvas->setMatrix(mat);
605     canvas->drawPicture(picture);
606     canvas->restoreToCount(saveCount);
607     canvas->flush();
608 }
609
610 ///////////////////////////////////////////////////////////////////////////////////////////////
611
612 /**
613  * Copies the entirety of the src bitmap (typically a tile) into a portion of the dst bitmap.
614  * If the src bitmap is too large to fit within the dst bitmap after the x and y
615  * offsets have been applied, any excess will be ignored (so only the top-left portion of the
616  * src bitmap will be copied).
617  *
618  * @param src source bitmap
619  * @param dst destination bitmap
620  * @param xOffset x-offset within destination bitmap
621  * @param yOffset y-offset within destination bitmap
622  */
623 static void bitmapCopyAtOffset(const SkBitmap& src, SkBitmap* dst,
624                                int xOffset, int yOffset) {
625     for (int y = 0; y <src.height() && y + yOffset < dst->height() ; y++) {
626         for (int x = 0; x < src.width() && x + xOffset < dst->width() ; x++) {
627             *dst->getAddr32(xOffset + x, yOffset + y) = *src.getAddr32(x, y);
628         }
629     }
630 }
631
632 bool TiledPictureRenderer::nextTile(int &i, int &j) {
633     if (++fCurrentTileOffset < fTileRects.count()) {
634         i = fCurrentTileOffset % fTilesX;
635         j = fCurrentTileOffset / fTilesX;
636         return true;
637     }
638     return false;
639 }
640
641 void TiledPictureRenderer::drawCurrentTile() {
642     SkASSERT(fCurrentTileOffset >= 0 && fCurrentTileOffset < fTileRects.count());
643     draw_tile_to_canvas(fCanvas, fTileRects[fCurrentTileOffset], fPicture);
644 }
645
646 bool TiledPictureRenderer::render(SkBitmap** out) {
647     SkASSERT(fPicture != NULL);
648     if (NULL == fPicture) {
649         return false;
650     }
651
652     SkBitmap bitmap;
653     if (out){
654         *out = SkNEW(SkBitmap);
655         setup_bitmap(*out, SkScalarCeilToInt(fPicture->cullRect().width()), 
656                            SkScalarCeilToInt(fPicture->cullRect().height()));
657         setup_bitmap(&bitmap, fTileWidth, fTileHeight);
658     }
659     bool success = true;
660     for (int i = 0; i < fTileRects.count(); ++i) {
661         draw_tile_to_canvas(fCanvas, fTileRects[i], fPicture);
662         if (fEnableWrites) {
663             success &= write(fCanvas, fWritePath, fMismatchPath, fInputFilename, fJsonSummaryPtr,
664                              fUseChecksumBasedFilenames, &i);
665         }
666         if (out) {
667             if (fCanvas->readPixels(&bitmap, 0, 0)) {
668                 // Add this tile to the entire bitmap.
669                 bitmapCopyAtOffset(bitmap, *out, SkScalarFloorToInt(fTileRects[i].left()),
670                                    SkScalarFloorToInt(fTileRects[i].top()));
671             } else {
672                 success = false;
673             }
674         }
675     }
676     return success;
677 }
678
679 SkCanvas* TiledPictureRenderer::setupCanvas(int width, int height) {
680     SkCanvas* canvas = this->INHERITED::setupCanvas(width, height);
681     SkASSERT(fPicture);
682     // Clip the tile to an area that is completely inside both the SkPicture and the viewport. This
683     // is mostly important for tiles on the right and bottom edges as they may go over this area and
684     // the picture may have some commands that draw outside of this area and so should not actually
685     // be written.
686     // Uses a clipRegion so that it will be unaffected by the scale factor, which may have been set
687     // by INHERITED::setupCanvas.
688     SkRegion clipRegion;
689     clipRegion.setRect(0, 0, this->getViewWidth(), this->getViewHeight());
690     canvas->clipRegion(clipRegion);
691     return canvas;
692 }
693
694 SkString TiledPictureRenderer::getConfigNameInternal() {
695     SkString name;
696     if (fTileMinPowerOf2Width > 0) {
697         name.append("pow2tile_");
698         name.appendf("%i", fTileMinPowerOf2Width);
699     } else {
700         name.append("tile_");
701         if (fTileWidthPercentage > 0) {
702             name.appendf("%.f%%", fTileWidthPercentage);
703         } else {
704             name.appendf("%i", fTileWidth);
705         }
706     }
707     name.append("x");
708     if (fTileHeightPercentage > 0) {
709         name.appendf("%.f%%", fTileHeightPercentage);
710     } else {
711         name.appendf("%i", fTileHeight);
712     }
713     return name;
714 }
715
716 ///////////////////////////////////////////////////////////////////////////////////////////////
717
718 void PlaybackCreationRenderer::setup() {
719     SkAutoTDelete<SkBBHFactory> factory(this->getFactory());
720     fRecorder.reset(SkNEW(SkPictureRecorder));
721     SkCanvas* canvas = fRecorder->beginRecording(SkIntToScalar(this->getViewWidth()), 
722                                                  SkIntToScalar(this->getViewHeight()),
723                                                  factory.get(),
724                                                  this->recordFlags());
725     this->scaleToScaleFactor(canvas);
726     canvas->drawPicture(fPicture);
727 }
728
729 bool PlaybackCreationRenderer::render(SkBitmap** out) {
730     fPicture.reset(fRecorder->endRecording());
731     // Since this class does not actually render, return false.
732     return false;
733 }
734
735 SkString PlaybackCreationRenderer::getConfigNameInternal() {
736     return SkString("playback_creation");
737 }
738
739 ///////////////////////////////////////////////////////////////////////////////////////////////
740 // SkPicture variants for each BBoxHierarchy type
741
742 SkBBHFactory* PictureRenderer::getFactory() {
743     switch (fBBoxHierarchyType) {
744         case kNone_BBoxHierarchyType:
745             return NULL;
746         case kRTree_BBoxHierarchyType:
747             return SkNEW(SkRTreeFactory);
748         case kTileGrid_BBoxHierarchyType:
749             return SkNEW_ARGS(SkTileGridFactory, (fGridInfo));
750     }
751     SkASSERT(0); // invalid bbhType
752     return NULL;
753 }
754
755 ///////////////////////////////////////////////////////////////////////////////
756
757 class GatherRenderer : public PictureRenderer {
758 public:
759 #if SK_SUPPORT_GPU
760     GatherRenderer(const GrContext::Options& opts) : INHERITED(opts) { }
761 #endif
762
763     virtual bool render(SkBitmap** out = NULL) SK_OVERRIDE {
764         SkRect bounds = SkRect::MakeWH(SkIntToScalar(fPicture->cullRect().width()),
765                                        SkIntToScalar(fPicture->cullRect().height()));
766         SkData* data = SkPictureUtils::GatherPixelRefs(fPicture, bounds);
767         SkSafeUnref(data);
768
769         return (fWritePath.isEmpty());    // we don't have anything to write
770     }
771
772 private:
773     virtual SkString getConfigNameInternal() SK_OVERRIDE {
774         return SkString("gather_pixelrefs");
775     }
776
777     typedef PictureRenderer INHERITED;
778 };
779
780 #if SK_SUPPORT_GPU
781 PictureRenderer* CreateGatherPixelRefsRenderer(const GrContext::Options& opts) {
782     return SkNEW_ARGS(GatherRenderer, (opts));
783 }
784 #else
785 PictureRenderer* CreateGatherPixelRefsRenderer() {
786     return SkNEW(GatherRenderer);
787 }
788 #endif
789
790 } // namespace sk_tools