blob: 2730a23f52c4f334b377606256c8ed16595b9a56 [file] [log] [blame]
keyar@chromium.orgb3fb7c12012-08-20 21:02:49 +00001/*
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
keyar@chromium.org451bb9f2012-07-26 17:27:57 +00008#include "PictureRenderer.h"
scroggo@google.com58b4ead2012-08-31 16:15:22 +00009#include "picture_utils.h"
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000010#include "SamplePipeControllers.h"
11#include "SkCanvas.h"
scroggo@google.com1b1bcc32013-05-21 20:31:23 +000012#include "SkData.h"
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000013#include "SkDevice.h"
14#include "SkGPipe.h"
scroggo@google.com58b4ead2012-08-31 16:15:22 +000015#if SK_SUPPORT_GPU
robertphillips@google.comfe1b5362013-02-07 19:45:46 +000016#include "gl/GrGLDefines.h"
scroggo@google.com58b4ead2012-08-31 16:15:22 +000017#include "SkGpuDevice.h"
18#endif
19#include "SkGraphics.h"
20#include "SkImageEncoder.h"
caryclark@google.coma3622372012-11-06 21:26:13 +000021#include "SkMaskFilter.h"
keyar@chromium.orgea826952012-08-23 15:24:13 +000022#include "SkMatrix.h"
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000023#include "SkPicture.h"
scroggo@google.com1b1bcc32013-05-21 20:31:23 +000024#include "SkPictureUtils.h"
25#include "SkPixelRef.h"
junov@chromium.org9313ca42012-11-02 18:11:49 +000026#include "SkRTree.h"
keyar@chromium.orgea826952012-08-23 15:24:13 +000027#include "SkScalar.h"
scroggo@google.coma9e3a362012-11-07 17:52:48 +000028#include "SkStream.h"
keyar@chromium.org9299ede2012-08-21 19:05:08 +000029#include "SkString.h"
scroggo@google.com58b4ead2012-08-31 16:15:22 +000030#include "SkTemplates.h"
junov@chromium.org3cb834b2012-12-13 16:39:53 +000031#include "SkTileGridPicture.h"
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000032#include "SkTDArray.h"
scroggo@google.com58b4ead2012-08-31 16:15:22 +000033#include "SkThreadUtils.h"
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000034#include "SkTypes.h"
keyar@chromium.org4ea96c52012-08-20 15:03:29 +000035
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000036namespace sk_tools {
37
38enum {
39 kDefaultTileWidth = 256,
40 kDefaultTileHeight = 256
41};
42
keyar@chromium.org9d696c02012-08-07 17:11:33 +000043void PictureRenderer::init(SkPicture* pict) {
keyar@chromium.org78a35c52012-08-20 15:03:44 +000044 SkASSERT(NULL == fPicture);
45 SkASSERT(NULL == fCanvas.get());
46 if (fPicture != NULL || NULL != fCanvas.get()) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +000047 return;
48 }
49
50 SkASSERT(pict != NULL);
keyar@chromium.org78a35c52012-08-20 15:03:44 +000051 if (NULL == pict) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +000052 return;
53 }
54
55 fPicture = pict;
junov@chromium.org9313ca42012-11-02 18:11:49 +000056 fPicture->ref();
keyar@chromium.orga474ce32012-08-20 15:03:57 +000057 fCanvas.reset(this->setupCanvas());
58}
59
caryclark@google.coma3622372012-11-06 21:26:13 +000060class FlagsDrawFilter : public SkDrawFilter {
61public:
62 FlagsDrawFilter(PictureRenderer::DrawFilterFlags* flags) :
63 fFlags(flags) {}
64
reed@google.com971aca72012-11-26 20:26:54 +000065 virtual bool filter(SkPaint* paint, Type t) {
caryclark@google.coma3622372012-11-06 21:26:13 +000066 paint->setFlags(paint->getFlags() & ~fFlags[t] & SkPaint::kAllFlags);
robertphillips@google.com49149312013-07-03 15:34:35 +000067 if (PictureRenderer::kMaskFilter_DrawFilterFlag & fFlags[t]) {
caryclark@google.coma3622372012-11-06 21:26:13 +000068 SkMaskFilter* maskFilter = paint->getMaskFilter();
robertphillips@google.com49149312013-07-03 15:34:35 +000069 if (NULL != maskFilter) {
reed@google.com457d8a72012-12-18 18:20:44 +000070 paint->setMaskFilter(NULL);
caryclark@google.coma3622372012-11-06 21:26:13 +000071 }
72 }
73 if (PictureRenderer::kHinting_DrawFilterFlag & fFlags[t]) {
74 paint->setHinting(SkPaint::kNo_Hinting);
75 } else if (PictureRenderer::kSlightHinting_DrawFilterFlag & fFlags[t]) {
76 paint->setHinting(SkPaint::kSlight_Hinting);
77 }
reed@google.com971aca72012-11-26 20:26:54 +000078 return true;
caryclark@google.coma3622372012-11-06 21:26:13 +000079 }
80
81private:
82 PictureRenderer::DrawFilterFlags* fFlags;
83};
84
scroggo@google.com82ec0b02012-12-17 19:25:54 +000085static void setUpFilter(SkCanvas* canvas, PictureRenderer::DrawFilterFlags* drawFilters) {
caryclark@google.coma3622372012-11-06 21:26:13 +000086 if (drawFilters && !canvas->getDrawFilter()) {
87 canvas->setDrawFilter(SkNEW_ARGS(FlagsDrawFilter, (drawFilters)))->unref();
caryclark@google.come3e940c2012-11-07 16:42:17 +000088 if (drawFilters[0] & PictureRenderer::kAAClip_DrawFilterFlag) {
89 canvas->setAllowSoftClip(false);
90 }
caryclark@google.coma3622372012-11-06 21:26:13 +000091 }
caryclark@google.coma3622372012-11-06 21:26:13 +000092}
93
keyar@chromium.orga474ce32012-08-20 15:03:57 +000094SkCanvas* PictureRenderer::setupCanvas() {
scroggo@google.comc0d5e542012-12-13 21:40:48 +000095 const int width = this->getViewWidth();
96 const int height = this->getViewHeight();
97 return this->setupCanvas(width, height);
keyar@chromium.orga474ce32012-08-20 15:03:57 +000098}
99
100SkCanvas* PictureRenderer::setupCanvas(int width, int height) {
caryclark@google.coma3622372012-11-06 21:26:13 +0000101 SkCanvas* canvas;
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000102 switch(fDeviceType) {
103 case kBitmap_DeviceType: {
104 SkBitmap bitmap;
keyar@chromium.orga474ce32012-08-20 15:03:57 +0000105 sk_tools::setup_bitmap(&bitmap, width, height);
caryclark@google.coma3622372012-11-06 21:26:13 +0000106 canvas = SkNEW_ARGS(SkCanvas, (bitmap));
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000107 }
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000108 break;
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000109#if SK_SUPPORT_GPU
scroggo@google.com0556ea02013-02-08 19:38:21 +0000110#if SK_ANGLE
111 case kAngle_DeviceType:
112 // fall through
113#endif
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000114 case kGPU_DeviceType: {
commit-bot@chromium.orgae403b92013-04-10 17:27:30 +0000115 SkAutoTUnref<GrSurface> target;
scroggo@google.com0556ea02013-02-08 19:38:21 +0000116 if (fGrContext) {
117 // create a render target to back the device
118 GrTextureDesc desc;
119 desc.fConfig = kSkia8888_GrPixelConfig;
120 desc.fFlags = kRenderTarget_GrTextureFlagBit;
121 desc.fWidth = width;
122 desc.fHeight = height;
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000123 desc.fSampleCnt = fSampleCount;
commit-bot@chromium.orgae403b92013-04-10 17:27:30 +0000124 target.reset(fGrContext->createUncachedTexture(desc, NULL, 0));
scroggo@google.com0556ea02013-02-08 19:38:21 +0000125 }
commit-bot@chromium.orgae403b92013-04-10 17:27:30 +0000126 if (NULL == target.get()) {
scroggo@google.com0556ea02013-02-08 19:38:21 +0000127 SkASSERT(0);
128 return NULL;
129 }
130
commit-bot@chromium.orgae403b92013-04-10 17:27:30 +0000131 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(target));
caryclark@google.coma3622372012-11-06 21:26:13 +0000132 canvas = SkNEW_ARGS(SkCanvas, (device.get()));
scroggo@google.com0556ea02013-02-08 19:38:21 +0000133 break;
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000134 }
135#endif
136 default:
137 SkASSERT(0);
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000138 return NULL;
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000139 }
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000140 setUpFilter(canvas, fDrawFilters);
141 this->scaleToScaleFactor(canvas);
142 return canvas;
143}
keyar@chromium.orga474ce32012-08-20 15:03:57 +0000144
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000145void PictureRenderer::scaleToScaleFactor(SkCanvas* canvas) {
146 SkASSERT(canvas != NULL);
147 if (fScaleFactor != SK_Scalar1) {
148 canvas->scale(fScaleFactor, fScaleFactor);
149 }
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000150}
151
152void PictureRenderer::end() {
scroggo@google.com08085f82013-01-28 20:40:24 +0000153 this->resetState(true);
junov@chromium.org9313ca42012-11-02 18:11:49 +0000154 SkSafeUnref(fPicture);
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000155 fPicture = NULL;
156 fCanvas.reset(NULL);
157}
158
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000159int PictureRenderer::getViewWidth() {
160 SkASSERT(fPicture != NULL);
robertphillips@google.com8ac811e2013-02-07 00:13:34 +0000161 int width = SkScalarCeilToInt(fPicture->width() * fScaleFactor);
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000162 if (fViewport.width() > 0) {
163 width = SkMin32(width, fViewport.width());
164 }
165 return width;
166}
167
168int PictureRenderer::getViewHeight() {
169 SkASSERT(fPicture != NULL);
robertphillips@google.com8ac811e2013-02-07 00:13:34 +0000170 int height = SkScalarCeilToInt(fPicture->height() * fScaleFactor);
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000171 if (fViewport.height() > 0) {
172 height = SkMin32(height, fViewport.height());
173 }
174 return height;
175}
176
junov@chromium.org9313ca42012-11-02 18:11:49 +0000177/** Converts fPicture to a picture that uses a BBoxHierarchy.
178 * PictureRenderer subclasses that are used to test picture playback
179 * should call this method during init.
180 */
181void PictureRenderer::buildBBoxHierarchy() {
182 SkASSERT(NULL != fPicture);
183 if (kNone_BBoxHierarchyType != fBBoxHierarchyType && NULL != fPicture) {
184 SkPicture* newPicture = this->createPicture();
185 SkCanvas* recorder = newPicture->beginRecording(fPicture->width(), fPicture->height(),
186 this->recordFlags());
187 fPicture->draw(recorder);
188 newPicture->endRecording();
189 fPicture->unref();
190 fPicture = newPicture;
191 }
192}
193
scroggo@google.com08085f82013-01-28 20:40:24 +0000194void PictureRenderer::resetState(bool callFinish) {
keyar@chromium.org28136b32012-08-20 15:04:15 +0000195#if SK_SUPPORT_GPU
robertphillips@google.com6177e692013-02-28 20:16:25 +0000196 SkGLContextHelper* glContext = this->getGLContext();
scroggo@google.com0556ea02013-02-08 19:38:21 +0000197 if (NULL == glContext) {
198 SkASSERT(kBitmap_DeviceType == fDeviceType);
199 return;
200 }
keyar@chromium.org28136b32012-08-20 15:04:15 +0000201
scroggo@google.com0556ea02013-02-08 19:38:21 +0000202 fGrContext->flush();
203 if (callFinish) {
204 SK_GL(*glContext, Finish());
keyar@chromium.org77a55222012-08-20 15:03:47 +0000205 }
keyar@chromium.orga40c20d2012-08-20 15:04:12 +0000206#endif
keyar@chromium.org77a55222012-08-20 15:03:47 +0000207}
208
junov@chromium.org9313ca42012-11-02 18:11:49 +0000209uint32_t PictureRenderer::recordFlags() {
junov@chromium.org100b1c52013-01-16 20:12:22 +0000210 return ((kNone_BBoxHierarchyType == fBBoxHierarchyType) ? 0 :
211 SkPicture::kOptimizeForClippedPlayback_RecordingFlag) |
212 SkPicture::kUsePathBoundsForClip_RecordingFlag;
junov@chromium.org9313ca42012-11-02 18:11:49 +0000213}
214
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000215/**
216 * Write the canvas to the specified path.
217 * @param canvas Must be non-null. Canvas to be written to a file.
218 * @param path Path for the file to be written. Should have no extension; write() will append
219 * an appropriate one. Passed in by value so it can be modified.
220 * @return bool True if the Canvas is written to a file.
221 */
222static bool write(SkCanvas* canvas, SkString path) {
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000223 SkASSERT(canvas != NULL);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000224 if (NULL == canvas) {
keyar@chromium.org9299ede2012-08-21 19:05:08 +0000225 return false;
226 }
227
228 SkBitmap bitmap;
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000229 SkISize size = canvas->getDeviceSize();
230 sk_tools::setup_bitmap(&bitmap, size.width(), size.height());
keyar@chromium.org9299ede2012-08-21 19:05:08 +0000231
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000232 canvas->readPixels(&bitmap, 0, 0);
keyar@chromium.org9299ede2012-08-21 19:05:08 +0000233 sk_tools::force_all_opaque(bitmap);
234
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000235 // Since path is passed in by value, it is okay to modify it.
236 path.append(".png");
keyar@chromium.org9299ede2012-08-21 19:05:08 +0000237 return SkImageEncoder::EncodeFile(path.c_str(), bitmap, SkImageEncoder::kPNG_Type, 100);
238}
239
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000240/**
241 * If path is non NULL, append number to it, and call write(SkCanvas*, SkString) to write the
242 * provided canvas to a file. Returns true if path is NULL or if write() succeeds.
243 */
244static bool writeAppendNumber(SkCanvas* canvas, const SkString* path, int number) {
245 if (NULL == path) {
246 return true;
247 }
248 SkString pathWithNumber(*path);
249 pathWithNumber.appendf("%i", number);
250 return write(canvas, pathWithNumber);
251}
252
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000253///////////////////////////////////////////////////////////////////////////////////////////////
254
djsollen@google.comfd9720c2012-11-06 16:54:40 +0000255SkCanvas* RecordPictureRenderer::setupCanvas(int width, int height) {
256 // defer the canvas setup until the render step
257 return NULL;
258}
259
scroggo@google.com1b1bcc32013-05-21 20:31:23 +0000260static SkData* encode_bitmap_to_data(size_t* offset, const SkBitmap& bm) {
261 SkPixelRef* pr = bm.pixelRef();
262 if (pr != NULL) {
263 SkData* data = pr->refEncodedData();
264 if (data != NULL) {
265 *offset = bm.pixelRefOffset();
266 return data;
267 }
268 }
269 *offset = 0;
270 return SkImageEncoder::EncodeData(bm, SkImageEncoder::kPNG_Type, 100);
scroggo@google.coma9e3a362012-11-07 17:52:48 +0000271}
272
edisonn@google.com84f548c2012-12-18 22:24:03 +0000273bool RecordPictureRenderer::render(const SkString* path, SkBitmap** out) {
junov@chromium.org9313ca42012-11-02 18:11:49 +0000274 SkAutoTUnref<SkPicture> replayer(this->createPicture());
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000275 SkCanvas* recorder = replayer->beginRecording(this->getViewWidth(), this->getViewHeight(),
junov@chromium.org9313ca42012-11-02 18:11:49 +0000276 this->recordFlags());
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000277 this->scaleToScaleFactor(recorder);
scroggo@google.com9a412522012-09-07 15:21:18 +0000278 fPicture->draw(recorder);
junov@chromium.org9313ca42012-11-02 18:11:49 +0000279 replayer->endRecording();
scroggo@google.coma9e3a362012-11-07 17:52:48 +0000280 if (path != NULL) {
281 // Record the new picture as a new SKP with PNG encoded bitmaps.
282 SkString skpPath(*path);
283 // ".skp" was removed from 'path' before being passed in here.
284 skpPath.append(".skp");
285 SkFILEWStream stream(skpPath.c_str());
scroggo@google.com1b1bcc32013-05-21 20:31:23 +0000286 replayer->serialize(&stream, &encode_bitmap_to_data);
scroggo@google.coma9e3a362012-11-07 17:52:48 +0000287 return true;
288 }
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000289 return false;
scroggo@google.com9a412522012-09-07 15:21:18 +0000290}
291
scroggo@google.com0a049b82012-11-02 22:01:26 +0000292SkString RecordPictureRenderer::getConfigNameInternal() {
293 return SkString("record");
294}
295
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000296///////////////////////////////////////////////////////////////////////////////////////////////
297
edisonn@google.com84f548c2012-12-18 22:24:03 +0000298bool PipePictureRenderer::render(const SkString* path, SkBitmap** out) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000299 SkASSERT(fCanvas.get() != NULL);
300 SkASSERT(fPicture != NULL);
keyar@chromium.org78a35c52012-08-20 15:03:44 +0000301 if (NULL == fCanvas.get() || NULL == fPicture) {
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000302 return false;
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000303 }
304
305 PipeController pipeController(fCanvas.get());
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000306 SkGPipeWriter writer;
307 SkCanvas* pipeCanvas = writer.startRecording(&pipeController);
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000308 pipeCanvas->drawPicture(*fPicture);
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000309 writer.endRecording();
scroggo@google.com9a412522012-09-07 15:21:18 +0000310 fCanvas->flush();
borenet@google.com070d3542012-10-26 13:26:55 +0000311 if (NULL != path) {
312 return write(fCanvas, *path);
313 }
edisonn@google.com84f548c2012-12-18 22:24:03 +0000314 if (NULL != out) {
315 *out = SkNEW(SkBitmap);
316 setup_bitmap(*out, fPicture->width(), fPicture->height());
317 fCanvas->readPixels(*out, 0, 0);
skia.committer@gmail.coma7d8e3e2012-12-19 02:01:38 +0000318 }
borenet@google.com070d3542012-10-26 13:26:55 +0000319 return true;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000320}
321
scroggo@google.com0a049b82012-11-02 22:01:26 +0000322SkString PipePictureRenderer::getConfigNameInternal() {
323 return SkString("pipe");
324}
325
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000326///////////////////////////////////////////////////////////////////////////////////////////////
327
junov@chromium.org9313ca42012-11-02 18:11:49 +0000328void SimplePictureRenderer::init(SkPicture* picture) {
329 INHERITED::init(picture);
330 this->buildBBoxHierarchy();
331}
332
edisonn@google.com84f548c2012-12-18 22:24:03 +0000333bool SimplePictureRenderer::render(const SkString* path, SkBitmap** out) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000334 SkASSERT(fCanvas.get() != NULL);
335 SkASSERT(fPicture != NULL);
keyar@chromium.org78a35c52012-08-20 15:03:44 +0000336 if (NULL == fCanvas.get() || NULL == fPicture) {
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000337 return false;
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000338 }
339
340 fCanvas->drawPicture(*fPicture);
scroggo@google.com9a412522012-09-07 15:21:18 +0000341 fCanvas->flush();
borenet@google.com070d3542012-10-26 13:26:55 +0000342 if (NULL != path) {
343 return write(fCanvas, *path);
344 }
skia.committer@gmail.coma7d8e3e2012-12-19 02:01:38 +0000345
edisonn@google.com84f548c2012-12-18 22:24:03 +0000346 if (NULL != out) {
347 *out = SkNEW(SkBitmap);
348 setup_bitmap(*out, fPicture->width(), fPicture->height());
349 fCanvas->readPixels(*out, 0, 0);
350 }
351
borenet@google.com070d3542012-10-26 13:26:55 +0000352 return true;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000353}
354
scroggo@google.com0a049b82012-11-02 22:01:26 +0000355SkString SimplePictureRenderer::getConfigNameInternal() {
356 return SkString("simple");
357}
358
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000359///////////////////////////////////////////////////////////////////////////////////////////////
360
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000361TiledPictureRenderer::TiledPictureRenderer()
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000362 : fTileWidth(kDefaultTileWidth)
rileya@google.comb947b912012-08-29 17:35:07 +0000363 , fTileHeight(kDefaultTileHeight)
rileya@google.coma04dc022012-09-10 19:01:38 +0000364 , fTileWidthPercentage(0.0)
rileya@google.comb947b912012-08-29 17:35:07 +0000365 , fTileHeightPercentage(0.0)
scroggo@google.comcbcef702012-12-13 22:09:28 +0000366 , fTileMinPowerOf2Width(0)
367 , fCurrentTileOffset(-1)
368 , fTilesX(0)
369 , fTilesY(0) { }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000370
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000371void TiledPictureRenderer::init(SkPicture* pict) {
372 SkASSERT(pict != NULL);
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000373 SkASSERT(0 == fTileRects.count());
374 if (NULL == pict || fTileRects.count() != 0) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000375 return;
376 }
377
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000378 // Do not call INHERITED::init(), which would create a (potentially large) canvas which is not
379 // used by bench_pictures.
380 fPicture = pict;
junov@chromium.org9313ca42012-11-02 18:11:49 +0000381 fPicture->ref();
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000382 this->buildBBoxHierarchy();
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000383
384 if (fTileWidthPercentage > 0) {
robertphillips@google.com5d8d1862012-08-15 14:36:41 +0000385 fTileWidth = sk_float_ceil2int(float(fTileWidthPercentage * fPicture->width() / 100));
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000386 }
387 if (fTileHeightPercentage > 0) {
robertphillips@google.com5d8d1862012-08-15 14:36:41 +0000388 fTileHeight = sk_float_ceil2int(float(fTileHeightPercentage * fPicture->height() / 100));
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000389 }
390
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000391 if (fTileMinPowerOf2Width > 0) {
392 this->setupPowerOf2Tiles();
393 } else {
394 this->setupTiles();
395 }
scroggo@google.comcbcef702012-12-13 22:09:28 +0000396 fCanvas.reset(this->setupCanvas(fTileWidth, fTileHeight));
397 // Initialize to -1 so that the first call to nextTile will set this up to draw tile 0 on the
398 // first call to drawCurrentTile.
399 fCurrentTileOffset = -1;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000400}
401
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000402void TiledPictureRenderer::end() {
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000403 fTileRects.reset();
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000404 this->INHERITED::end();
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000405}
406
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000407void TiledPictureRenderer::setupTiles() {
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000408 // Only use enough tiles to cover the viewport
409 const int width = this->getViewWidth();
410 const int height = this->getViewHeight();
411
scroggo@google.comcbcef702012-12-13 22:09:28 +0000412 fTilesX = fTilesY = 0;
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000413 for (int tile_y_start = 0; tile_y_start < height; tile_y_start += fTileHeight) {
scroggo@google.comcbcef702012-12-13 22:09:28 +0000414 fTilesY++;
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000415 for (int tile_x_start = 0; tile_x_start < width; tile_x_start += fTileWidth) {
scroggo@google.comcbcef702012-12-13 22:09:28 +0000416 if (0 == tile_y_start) {
417 // Only count tiles in the X direction on the first pass.
418 fTilesX++;
419 }
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000420 *fTileRects.append() = SkRect::MakeXYWH(SkIntToScalar(tile_x_start),
421 SkIntToScalar(tile_y_start),
422 SkIntToScalar(fTileWidth),
423 SkIntToScalar(fTileHeight));
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000424 }
425 }
426}
427
scroggo@google.comcbcef702012-12-13 22:09:28 +0000428bool TiledPictureRenderer::tileDimensions(int &x, int &y) {
429 if (fTileRects.count() == 0 || NULL == fPicture) {
430 return false;
431 }
432 x = fTilesX;
433 y = fTilesY;
434 return true;
435}
436
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000437// The goal of the powers of two tiles is to minimize the amount of wasted tile
438// space in the width-wise direction and then minimize the number of tiles. The
439// constraints are that every tile must have a pixel width that is a power of
440// two and also be of some minimal width (that is also a power of two).
441//
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000442// This is solved by first taking our picture size and rounding it up to the
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000443// multiple of the minimal width. The binary representation of this rounded
444// value gives us the tiles we need: a bit of value one means we need a tile of
445// that size.
446void TiledPictureRenderer::setupPowerOf2Tiles() {
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000447 // Only use enough tiles to cover the viewport
448 const int width = this->getViewWidth();
449 const int height = this->getViewHeight();
450
451 int rounded_value = width;
452 if (width % fTileMinPowerOf2Width != 0) {
453 rounded_value = width - (width % fTileMinPowerOf2Width) + fTileMinPowerOf2Width;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000454 }
455
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000456 int num_bits = SkScalarCeilToInt(SkScalarLog2(SkIntToScalar(width)));
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000457 int largest_possible_tile_size = 1 << num_bits;
458
scroggo@google.comcbcef702012-12-13 22:09:28 +0000459 fTilesX = fTilesY = 0;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000460 // The tile height is constant for a particular picture.
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000461 for (int tile_y_start = 0; tile_y_start < height; tile_y_start += fTileHeight) {
scroggo@google.comcbcef702012-12-13 22:09:28 +0000462 fTilesY++;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000463 int tile_x_start = 0;
464 int current_width = largest_possible_tile_size;
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000465 // Set fTileWidth to be the width of the widest tile, so that each canvas is large enough
466 // to draw each tile.
467 fTileWidth = current_width;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000468
469 while (current_width >= fTileMinPowerOf2Width) {
470 // It is very important this is a bitwise AND.
471 if (current_width & rounded_value) {
scroggo@google.comcbcef702012-12-13 22:09:28 +0000472 if (0 == tile_y_start) {
473 // Only count tiles in the X direction on the first pass.
474 fTilesX++;
475 }
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000476 *fTileRects.append() = SkRect::MakeXYWH(SkIntToScalar(tile_x_start),
477 SkIntToScalar(tile_y_start),
478 SkIntToScalar(current_width),
479 SkIntToScalar(fTileHeight));
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000480 tile_x_start += current_width;
481 }
482
483 current_width >>= 1;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000484 }
485 }
486}
487
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000488/**
489 * Draw the specified playback to the canvas translated to rectangle provided, so that this mini
490 * canvas represents the rectangle's portion of the overall picture.
491 * Saves and restores so that the initial clip and matrix return to their state before this function
492 * is called.
493 */
494template<class T>
495static void DrawTileToCanvas(SkCanvas* canvas, const SkRect& tileRect, T* playback) {
496 int saveCount = canvas->save();
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000497 // Translate so that we draw the correct portion of the picture.
498 // Perform a postTranslate so that the scaleFactor does not interfere with the positioning.
499 SkMatrix mat(canvas->getTotalMatrix());
500 mat.postTranslate(-tileRect.fLeft, -tileRect.fTop);
501 canvas->setMatrix(mat);
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000502 playback->draw(canvas);
503 canvas->restoreToCount(saveCount);
504 canvas->flush();
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000505}
506
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000507///////////////////////////////////////////////////////////////////////////////////////////////
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000508
edisonn@google.com84f548c2012-12-18 22:24:03 +0000509static void bitmapCopySubset(const SkBitmap& src, SkBitmap* dst, int xDst,
510 int yDst) {
511 for (int y = 0; y <src.height() && y + yDst < dst->height() ; y++) {
512 for (int x = 0; x < src.width() && x + xDst < dst->width() ; x++) {
513 *dst->getAddr32(xDst + x, yDst + y) = *src.getAddr32(x, y);
514 }
515 }
516}
517
scroggo@google.comcbcef702012-12-13 22:09:28 +0000518bool TiledPictureRenderer::nextTile(int &i, int &j) {
519 if (++fCurrentTileOffset < fTileRects.count()) {
520 i = fCurrentTileOffset % fTilesX;
521 j = fCurrentTileOffset / fTilesX;
522 return true;
523 }
524 return false;
525}
526
527void TiledPictureRenderer::drawCurrentTile() {
528 SkASSERT(fCurrentTileOffset >= 0 && fCurrentTileOffset < fTileRects.count());
529 DrawTileToCanvas(fCanvas, fTileRects[fCurrentTileOffset], fPicture);
530}
531
edisonn@google.com84f548c2012-12-18 22:24:03 +0000532bool TiledPictureRenderer::render(const SkString* path, SkBitmap** out) {
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000533 SkASSERT(fPicture != NULL);
534 if (NULL == fPicture) {
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000535 return false;
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000536 }
537
edisonn@google.com84f548c2012-12-18 22:24:03 +0000538 SkBitmap bitmap;
539 if (out){
540 *out = SkNEW(SkBitmap);
541 setup_bitmap(*out, fPicture->width(), fPicture->height());
542 setup_bitmap(&bitmap, fTileWidth, fTileHeight);
543 }
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000544 bool success = true;
545 for (int i = 0; i < fTileRects.count(); ++i) {
scroggo@google.comcbcef702012-12-13 22:09:28 +0000546 DrawTileToCanvas(fCanvas, fTileRects[i], fPicture);
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000547 if (NULL != path) {
scroggo@google.comcbcef702012-12-13 22:09:28 +0000548 success &= writeAppendNumber(fCanvas, path, i);
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000549 }
edisonn@google.com84f548c2012-12-18 22:24:03 +0000550 if (NULL != out) {
551 if (fCanvas->readPixels(&bitmap, 0, 0)) {
jvanverth@google.com9c4e5ac2013-01-07 18:41:28 +0000552 bitmapCopySubset(bitmap, *out, SkScalarFloorToInt(fTileRects[i].left()),
553 SkScalarFloorToInt(fTileRects[i].top()));
edisonn@google.com84f548c2012-12-18 22:24:03 +0000554 } else {
555 success = false;
556 }
557 }
keyar@chromium.org163b5672012-08-01 17:53:29 +0000558 }
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000559 return success;
keyar@chromium.org163b5672012-08-01 17:53:29 +0000560}
561
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000562SkCanvas* TiledPictureRenderer::setupCanvas(int width, int height) {
563 SkCanvas* canvas = this->INHERITED::setupCanvas(width, height);
564 SkASSERT(fPicture != NULL);
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000565 // Clip the tile to an area that is completely inside both the SkPicture and the viewport. This
566 // is mostly important for tiles on the right and bottom edges as they may go over this area and
567 // the picture may have some commands that draw outside of this area and so should not actually
568 // be written.
569 // Uses a clipRegion so that it will be unaffected by the scale factor, which may have been set
570 // by INHERITED::setupCanvas.
571 SkRegion clipRegion;
572 clipRegion.setRect(0, 0, this->getViewWidth(), this->getViewHeight());
573 canvas->clipRegion(clipRegion);
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000574 return canvas;
575}
scroggo@google.com0a049b82012-11-02 22:01:26 +0000576
577SkString TiledPictureRenderer::getConfigNameInternal() {
578 SkString name;
579 if (fTileMinPowerOf2Width > 0) {
580 name.append("pow2tile_");
581 name.appendf("%i", fTileMinPowerOf2Width);
582 } else {
583 name.append("tile_");
584 if (fTileWidthPercentage > 0) {
585 name.appendf("%.f%%", fTileWidthPercentage);
586 } else {
587 name.appendf("%i", fTileWidth);
588 }
589 }
590 name.append("x");
591 if (fTileHeightPercentage > 0) {
592 name.appendf("%.f%%", fTileHeightPercentage);
593 } else {
594 name.appendf("%i", fTileHeight);
595 }
596 return name;
597}
598
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000599///////////////////////////////////////////////////////////////////////////////////////////////
600
601// Holds all of the information needed to draw a set of tiles.
602class CloneData : public SkRunnable {
603
604public:
605 CloneData(SkPicture* clone, SkCanvas* canvas, SkTDArray<SkRect>& rects, int start, int end,
606 SkRunnable* done)
607 : fClone(clone)
608 , fCanvas(canvas)
609 , fPath(NULL)
610 , fRects(rects)
611 , fStart(start)
612 , fEnd(end)
613 , fSuccess(NULL)
614 , fDone(done) {
615 SkASSERT(fDone != NULL);
616 }
617
618 virtual void run() SK_OVERRIDE {
619 SkGraphics::SetTLSFontCacheLimit(1024 * 1024);
edisonn@google.com84f548c2012-12-18 22:24:03 +0000620
621 SkBitmap bitmap;
622 if (fBitmap != NULL) {
623 // All tiles are the same size.
jvanverth@google.com9c4e5ac2013-01-07 18:41:28 +0000624 setup_bitmap(&bitmap, SkScalarFloorToInt(fRects[0].width()), SkScalarFloorToInt(fRects[0].height()));
edisonn@google.com84f548c2012-12-18 22:24:03 +0000625 }
skia.committer@gmail.coma7d8e3e2012-12-19 02:01:38 +0000626
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000627 for (int i = fStart; i < fEnd; i++) {
628 DrawTileToCanvas(fCanvas, fRects[i], fClone);
629 if (fPath != NULL && !writeAppendNumber(fCanvas, fPath, i)
630 && fSuccess != NULL) {
631 *fSuccess = false;
632 // If one tile fails to write to a file, do not continue drawing the rest.
633 break;
634 }
edisonn@google.com84f548c2012-12-18 22:24:03 +0000635 if (fBitmap != NULL) {
636 if (fCanvas->readPixels(&bitmap, 0, 0)) {
637 SkAutoLockPixels alp(*fBitmap);
jvanverth@google.com9c4e5ac2013-01-07 18:41:28 +0000638 bitmapCopySubset(bitmap, fBitmap, SkScalarFloorToInt(fRects[i].left()),
639 SkScalarFloorToInt(fRects[i].top()));
edisonn@google.com84f548c2012-12-18 22:24:03 +0000640 } else {
641 *fSuccess = false;
642 // If one tile fails to read pixels, do not continue drawing the rest.
643 break;
644 }
645 }
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000646 }
647 fDone->run();
648 }
649
650 void setPathAndSuccess(const SkString* path, bool* success) {
651 fPath = path;
652 fSuccess = success;
653 }
654
edisonn@google.com84f548c2012-12-18 22:24:03 +0000655 void setBitmap(SkBitmap* bitmap) {
656 fBitmap = bitmap;
657 }
658
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000659private:
660 // All pointers unowned.
661 SkPicture* fClone; // Picture to draw from. Each CloneData has a unique one which
662 // is threadsafe.
663 SkCanvas* fCanvas; // Canvas to draw to. Reused for each tile.
664 const SkString* fPath; // If non-null, path to write the result to as a PNG.
665 SkTDArray<SkRect>& fRects; // All tiles of the picture.
666 const int fStart; // Range of tiles drawn by this thread.
667 const int fEnd;
668 bool* fSuccess; // Only meaningful if path is non-null. Shared by all threads,
669 // and only set to false upon failure to write to a PNG.
670 SkRunnable* fDone;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000671 SkBitmap* fBitmap;
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000672};
673
674MultiCorePictureRenderer::MultiCorePictureRenderer(int threadCount)
675: fNumThreads(threadCount)
676, fThreadPool(threadCount)
677, fCountdown(threadCount) {
678 // Only need to create fNumThreads - 1 clones, since one thread will use the base
679 // picture.
680 fPictureClones = SkNEW_ARRAY(SkPicture, fNumThreads - 1);
681 fCloneData = SkNEW_ARRAY(CloneData*, fNumThreads);
682}
683
684void MultiCorePictureRenderer::init(SkPicture *pict) {
685 // Set fPicture and the tiles.
686 this->INHERITED::init(pict);
687 for (int i = 0; i < fNumThreads; ++i) {
688 *fCanvasPool.append() = this->setupCanvas(this->getTileWidth(), this->getTileHeight());
689 }
690 // Only need to create fNumThreads - 1 clones, since one thread will use the base picture.
691 fPicture->clone(fPictureClones, fNumThreads - 1);
692 // Populate each thread with the appropriate data.
693 // Group the tiles into nearly equal size chunks, rounding up so we're sure to cover them all.
694 const int chunkSize = (fTileRects.count() + fNumThreads - 1) / fNumThreads;
695
696 for (int i = 0; i < fNumThreads; i++) {
697 SkPicture* pic;
698 if (i == fNumThreads-1) {
699 // The last set will use the original SkPicture.
700 pic = fPicture;
701 } else {
702 pic = &fPictureClones[i];
703 }
704 const int start = i * chunkSize;
705 const int end = SkMin32(start + chunkSize, fTileRects.count());
706 fCloneData[i] = SkNEW_ARGS(CloneData,
707 (pic, fCanvasPool[i], fTileRects, start, end, &fCountdown));
708 }
709}
710
edisonn@google.com84f548c2012-12-18 22:24:03 +0000711bool MultiCorePictureRenderer::render(const SkString *path, SkBitmap** out) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000712 bool success = true;
713 if (path != NULL) {
714 for (int i = 0; i < fNumThreads-1; i++) {
715 fCloneData[i]->setPathAndSuccess(path, &success);
716 }
717 }
718
edisonn@google.com84f548c2012-12-18 22:24:03 +0000719 if (NULL != out) {
720 *out = SkNEW(SkBitmap);
721 setup_bitmap(*out, fPicture->width(), fPicture->height());
722 for (int i = 0; i < fNumThreads; i++) {
723 fCloneData[i]->setBitmap(*out);
724 }
725 } else {
726 for (int i = 0; i < fNumThreads; i++) {
727 fCloneData[i]->setBitmap(NULL);
728 }
729 }
730
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000731 fCountdown.reset(fNumThreads);
732 for (int i = 0; i < fNumThreads; i++) {
733 fThreadPool.add(fCloneData[i]);
734 }
735 fCountdown.wait();
736
737 return success;
738}
739
740void MultiCorePictureRenderer::end() {
741 for (int i = 0; i < fNumThreads - 1; i++) {
742 SkDELETE(fCloneData[i]);
743 fCloneData[i] = NULL;
744 }
745
746 fCanvasPool.unrefAll();
747
748 this->INHERITED::end();
749}
750
751MultiCorePictureRenderer::~MultiCorePictureRenderer() {
752 // Each individual CloneData was deleted in end.
753 SkDELETE_ARRAY(fCloneData);
754 SkDELETE_ARRAY(fPictureClones);
755}
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000756
scroggo@google.com0a049b82012-11-02 22:01:26 +0000757SkString MultiCorePictureRenderer::getConfigNameInternal() {
758 SkString name = this->INHERITED::getConfigNameInternal();
759 name.appendf("_multi_%i_threads", fNumThreads);
760 return name;
761}
762
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000763///////////////////////////////////////////////////////////////////////////////////////////////
scroggo@google.com9a412522012-09-07 15:21:18 +0000764
765void PlaybackCreationRenderer::setup() {
junov@chromium.org9313ca42012-11-02 18:11:49 +0000766 fReplayer.reset(this->createPicture());
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000767 SkCanvas* recorder = fReplayer->beginRecording(this->getViewWidth(), this->getViewHeight(),
junov@chromium.org9313ca42012-11-02 18:11:49 +0000768 this->recordFlags());
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000769 this->scaleToScaleFactor(recorder);
scroggo@google.com9a412522012-09-07 15:21:18 +0000770 fPicture->draw(recorder);
771}
772
edisonn@google.com84f548c2012-12-18 22:24:03 +0000773bool PlaybackCreationRenderer::render(const SkString*, SkBitmap** out) {
junov@chromium.org9313ca42012-11-02 18:11:49 +0000774 fReplayer->endRecording();
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000775 // Since this class does not actually render, return false.
776 return false;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000777}
778
scroggo@google.com0a049b82012-11-02 22:01:26 +0000779SkString PlaybackCreationRenderer::getConfigNameInternal() {
780 return SkString("playback_creation");
781}
782
junov@chromium.org9313ca42012-11-02 18:11:49 +0000783///////////////////////////////////////////////////////////////////////////////////////////////
784// SkPicture variants for each BBoxHierarchy type
785
786class RTreePicture : public SkPicture {
787public:
788 virtual SkBBoxHierarchy* createBBoxHierarchy() const SK_OVERRIDE{
789 static const int kRTreeMinChildren = 6;
790 static const int kRTreeMaxChildren = 11;
791 SkScalar aspectRatio = SkScalarDiv(SkIntToScalar(fWidth),
792 SkIntToScalar(fHeight));
793 return SkRTree::Create(kRTreeMinChildren, kRTreeMaxChildren,
794 aspectRatio);
795 }
796};
797
798SkPicture* PictureRenderer::createPicture() {
799 switch (fBBoxHierarchyType) {
800 case kNone_BBoxHierarchyType:
801 return SkNEW(SkPicture);
802 case kRTree_BBoxHierarchyType:
803 return SkNEW(RTreePicture);
junov@chromium.org7b537062012-11-06 18:58:43 +0000804 case kTileGrid_BBoxHierarchyType:
junov@chromium.org29b19e52013-02-27 18:35:16 +0000805 return SkNEW_ARGS(SkTileGridPicture, (fPicture->width(),
806 fPicture->height(), fGridInfo));
junov@chromium.org9313ca42012-11-02 18:11:49 +0000807 }
808 SkASSERT(0); // invalid bbhType
809 return NULL;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000810}
junov@chromium.org9313ca42012-11-02 18:11:49 +0000811
reed@google.comfe7b1ed2012-11-29 21:00:39 +0000812///////////////////////////////////////////////////////////////////////////////
813
814class GatherRenderer : public PictureRenderer {
815public:
edisonn@google.com84f548c2012-12-18 22:24:03 +0000816 virtual bool render(const SkString* path, SkBitmap** out = NULL)
817 SK_OVERRIDE {
reed@google.comfe7b1ed2012-11-29 21:00:39 +0000818 SkRect bounds = SkRect::MakeWH(SkIntToScalar(fPicture->width()),
819 SkIntToScalar(fPicture->height()));
820 SkData* data = SkPictureUtils::GatherPixelRefs(fPicture, bounds);
821 SkSafeUnref(data);
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +0000822
reed@google.comfe7b1ed2012-11-29 21:00:39 +0000823 return NULL == path; // we don't have anything to write
824 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +0000825
reed@google.comfe7b1ed2012-11-29 21:00:39 +0000826private:
827 virtual SkString getConfigNameInternal() SK_OVERRIDE {
828 return SkString("gather_pixelrefs");
829 }
830};
831
832PictureRenderer* CreateGatherPixelRefsRenderer() {
833 return SkNEW(GatherRenderer);
834}
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +0000835
reed@google.com5a34fd32012-12-10 16:05:09 +0000836///////////////////////////////////////////////////////////////////////////////
837
838class PictureCloneRenderer : public PictureRenderer {
839public:
edisonn@google.com84f548c2012-12-18 22:24:03 +0000840 virtual bool render(const SkString* path, SkBitmap** out = NULL)
841 SK_OVERRIDE {
reed@google.com5a34fd32012-12-10 16:05:09 +0000842 for (int i = 0; i < 100; ++i) {
843 SkPicture* clone = fPicture->clone();
844 SkSafeUnref(clone);
845 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +0000846
reed@google.com5a34fd32012-12-10 16:05:09 +0000847 return NULL == path; // we don't have anything to write
848 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +0000849
reed@google.com5a34fd32012-12-10 16:05:09 +0000850private:
851 virtual SkString getConfigNameInternal() SK_OVERRIDE {
852 return SkString("picture_clone");
853 }
854};
855
856PictureRenderer* CreatePictureCloneRenderer() {
857 return SkNEW(PictureCloneRenderer);
858}
859
junov@chromium.org9313ca42012-11-02 18:11:49 +0000860} // namespace sk_tools