blob: c827be603cef6d904008159ec268e4d735e5cd76 [file] [log] [blame]
junov@google.com4370aed2012-01-18 16:21:08 +00001
2/*
junov@chromium.org10f7f972012-07-31 21:01:51 +00003 * Copyright 2012 Google Inc.
junov@google.com4370aed2012-01-18 16:21:08 +00004 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#include "SkDeferredCanvas.h"
10
junov@chromium.org88e29142012-08-07 16:48:22 +000011#include "SkChunkAlloc.h"
12#include "SkColorFilter.h"
13#include "SkDevice.h"
14#include "SkDrawFilter.h"
15#include "SkGPipe.h"
junov@google.com4370aed2012-01-18 16:21:08 +000016#include "SkPaint.h"
reed@google.com4ed0fb72012-12-12 20:48:18 +000017#include "SkRRect.h"
junov@google.com4370aed2012-01-18 16:21:08 +000018#include "SkShader.h"
junov@google.com4370aed2012-01-18 16:21:08 +000019
junov@chromium.orgbfeddae2012-07-23 13:35:14 +000020enum {
21 // Deferred canvas will auto-flush when recording reaches this limit
22 kDefaultMaxRecordingStorageBytes = 64*1024*1024,
sugoi@google.com5347de12012-11-21 16:44:45 +000023 kDeferredCanvasBitmapSizeThreshold = ~0, // Disables this feature
junov@chromium.orgbfeddae2012-07-23 13:35:14 +000024};
25
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +000026enum PlaybackMode {
27 kNormal_PlaybackMode,
28 kSilent_PlaybackMode,
29};
30
junov@google.com4370aed2012-01-18 16:21:08 +000031namespace {
sugoi@google.com7775fd52012-11-21 15:47:04 +000032bool shouldDrawImmediately(const SkBitmap* bitmap, const SkPaint* paint,
33 size_t bitmapSizeThreshold) {
34 if (bitmap && ((bitmap->getTexture() && !bitmap->isImmutable()) ||
35 (bitmap->getSize() > bitmapSizeThreshold))) {
junov@chromium.org10f7f972012-07-31 21:01:51 +000036 return true;
37 }
38 if (paint) {
39 SkShader* shader = paint->getShader();
40 // Here we detect the case where the shader is an SkBitmapProcShader
41 // with a gpu texture attached. Checking this without RTTI
42 // requires making the assumption that only gradient shaders
43 // and SkBitmapProcShader implement asABitmap(). The following
44 // code may need to be revised if that assumption is ever broken.
45 if (shader && !shader->asAGradient(NULL)) {
46 SkBitmap bm;
rmistry@google.comd6176b02012-08-23 18:14:13 +000047 if (shader->asABitmap(&bm, NULL, NULL) &&
junov@chromium.org10f7f972012-07-31 21:01:51 +000048 NULL != bm.getTexture()) {
49 return true;
50 }
51 }
52 }
53 return false;
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +000054}
55}
56
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +000057namespace {
junov@google.com4370aed2012-01-18 16:21:08 +000058
rmistry@google.comd6176b02012-08-23 18:14:13 +000059bool isPaintOpaque(const SkPaint* paint,
junov@chromium.orgc16ca922012-02-24 22:06:27 +000060 const SkBitmap* bmpReplacesShader = NULL) {
junov@google.com4370aed2012-01-18 16:21:08 +000061 // TODO: SkXfermode should have a virtual isOpaque method, which would
62 // make it possible to test modes that do not have a Coeff representation.
junov@chromium.org87f982c2012-02-23 21:34:34 +000063
64 if (!paint) {
65 return bmpReplacesShader ? bmpReplacesShader->isOpaque() : true;
66 }
67
junov@google.com4370aed2012-01-18 16:21:08 +000068 SkXfermode::Coeff srcCoeff, dstCoeff;
junov@chromium.org87f982c2012-02-23 21:34:34 +000069 if (SkXfermode::AsCoeff(paint->getXfermode(), &srcCoeff, &dstCoeff)){
junov@chromium.org8cef67a2012-10-11 20:19:15 +000070 if (SkXfermode::kDA_Coeff == srcCoeff || SkXfermode::kDC_Coeff == srcCoeff ||
71 SkXfermode::kIDA_Coeff == srcCoeff || SkXfermode::kIDC_Coeff == srcCoeff) {
72 return false;
73 }
junov@google.com4370aed2012-01-18 16:21:08 +000074 switch (dstCoeff) {
75 case SkXfermode::kZero_Coeff:
76 return true;
77 case SkXfermode::kISA_Coeff:
junov@chromium.org87f982c2012-02-23 21:34:34 +000078 if (paint->getAlpha() != 255) {
junov@google.com4370aed2012-01-18 16:21:08 +000079 break;
80 }
81 if (bmpReplacesShader) {
82 if (!bmpReplacesShader->isOpaque()) {
83 break;
84 }
junov@chromium.org87f982c2012-02-23 21:34:34 +000085 } else if (paint->getShader() && !paint->getShader()->isOpaque()) {
junov@google.com4370aed2012-01-18 16:21:08 +000086 break;
87 }
rmistry@google.comd6176b02012-08-23 18:14:13 +000088 if (paint->getColorFilter() &&
junov@chromium.orgc16ca922012-02-24 22:06:27 +000089 ((paint->getColorFilter()->getFlags() &
junov@google.com4370aed2012-01-18 16:21:08 +000090 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
91 break;
92 }
93 return true;
94 case SkXfermode::kSA_Coeff:
junov@chromium.org87f982c2012-02-23 21:34:34 +000095 if (paint->getAlpha() != 0) {
junov@google.com4370aed2012-01-18 16:21:08 +000096 break;
97 }
rmistry@google.comd6176b02012-08-23 18:14:13 +000098 if (paint->getColorFilter() &&
junov@chromium.orgc16ca922012-02-24 22:06:27 +000099 ((paint->getColorFilter()->getFlags() &
junov@google.com4370aed2012-01-18 16:21:08 +0000100 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
101 break;
102 }
103 return true;
104 case SkXfermode::kSC_Coeff:
junov@chromium.org87f982c2012-02-23 21:34:34 +0000105 if (paint->getColor() != 0) { // all components must be 0
junov@google.com4370aed2012-01-18 16:21:08 +0000106 break;
107 }
junov@chromium.org87f982c2012-02-23 21:34:34 +0000108 if (bmpReplacesShader || paint->getShader()) {
junov@google.com4370aed2012-01-18 16:21:08 +0000109 break;
110 }
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000111 if (paint->getColorFilter() && (
112 (paint->getColorFilter()->getFlags() &
junov@google.com4370aed2012-01-18 16:21:08 +0000113 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
114 break;
115 }
116 return true;
117 default:
118 break;
119 }
120 }
121 return false;
122}
123
124} // unnamed namespace
125
junov@chromium.org88e29142012-08-07 16:48:22 +0000126//-----------------------------------------------------------------------------
127// DeferredPipeController
128//-----------------------------------------------------------------------------
129
130class DeferredPipeController : public SkGPipeController {
131public:
132 DeferredPipeController();
133 void setPlaybackCanvas(SkCanvas*);
134 virtual ~DeferredPipeController();
135 virtual void* requestBlock(size_t minRequest, size_t* actual) SK_OVERRIDE;
136 virtual void notifyWritten(size_t bytes) SK_OVERRIDE;
junov@chromium.orgfb103892012-09-20 19:35:43 +0000137 void playback(bool silent);
junov@chromium.orga38dfb62012-09-20 22:10:33 +0000138 bool hasPendingCommands() const { return fAllocator.blockCount() != 0; }
junov@chromium.org88e29142012-08-07 16:48:22 +0000139 size_t storageAllocatedForRecording() const { return fAllocator.totalCapacity(); }
140private:
141 enum {
142 kMinBlockSize = 4096
143 };
144 struct PipeBlock {
145 PipeBlock(void* block, size_t size) { fBlock = block, fSize = size; }
146 void* fBlock;
147 size_t fSize;
148 };
149 void* fBlock;
150 size_t fBytesWritten;
151 SkChunkAlloc fAllocator;
152 SkTDArray<PipeBlock> fBlockList;
153 SkGPipeReader fReader;
154};
155
156DeferredPipeController::DeferredPipeController() :
157 fAllocator(kMinBlockSize) {
158 fBlock = NULL;
159 fBytesWritten = 0;
160}
161
162DeferredPipeController::~DeferredPipeController() {
163 fAllocator.reset();
164}
165
166void DeferredPipeController::setPlaybackCanvas(SkCanvas* canvas) {
167 fReader.setCanvas(canvas);
168}
169
170void* DeferredPipeController::requestBlock(size_t minRequest, size_t *actual) {
171 if (fBlock) {
172 // Save the previous block for later
173 PipeBlock previousBloc(fBlock, fBytesWritten);
174 fBlockList.push(previousBloc);
175 }
176 int32_t blockSize = SkMax32(minRequest, kMinBlockSize);
177 fBlock = fAllocator.allocThrow(blockSize);
178 fBytesWritten = 0;
179 *actual = blockSize;
180 return fBlock;
181}
182
183void DeferredPipeController::notifyWritten(size_t bytes) {
184 fBytesWritten += bytes;
185}
186
junov@chromium.orgfb103892012-09-20 19:35:43 +0000187void DeferredPipeController::playback(bool silent) {
188 uint32_t flags = silent ? SkGPipeReader::kSilent_PlaybackFlag : 0;
junov@chromium.org88e29142012-08-07 16:48:22 +0000189 for (int currentBlock = 0; currentBlock < fBlockList.count(); currentBlock++ ) {
junov@chromium.orgfb103892012-09-20 19:35:43 +0000190 fReader.playback(fBlockList[currentBlock].fBlock, fBlockList[currentBlock].fSize,
191 flags);
junov@chromium.org88e29142012-08-07 16:48:22 +0000192 }
193 fBlockList.reset();
194
195 if (fBlock) {
junov@chromium.orgfb103892012-09-20 19:35:43 +0000196 fReader.playback(fBlock, fBytesWritten, flags);
junov@chromium.org88e29142012-08-07 16:48:22 +0000197 fBlock = NULL;
198 }
199
200 // Release all allocated blocks
201 fAllocator.reset();
202}
203
junov@chromium.org88e29142012-08-07 16:48:22 +0000204//-----------------------------------------------------------------------------
205// DeferredDevice
206//-----------------------------------------------------------------------------
junov@chromium.org88e29142012-08-07 16:48:22 +0000207class DeferredDevice : public SkDevice {
208public:
209 DeferredDevice(SkDevice* immediateDevice,
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000210 SkDeferredCanvas::NotificationClient* notificationClient = NULL);
junov@chromium.org88e29142012-08-07 16:48:22 +0000211 ~DeferredDevice();
212
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000213 void setNotificationClient(SkDeferredCanvas::NotificationClient* notificationClient);
junov@chromium.org88e29142012-08-07 16:48:22 +0000214 SkCanvas* recordingCanvas();
215 SkCanvas* immediateCanvas() const {return fImmediateCanvas;}
216 SkDevice* immediateDevice() const {return fImmediateDevice;}
217 bool isFreshFrame();
junov@chromium.orga38dfb62012-09-20 22:10:33 +0000218 bool hasPendingCommands();
junov@chromium.org88e29142012-08-07 16:48:22 +0000219 size_t storageAllocatedForRecording() const;
220 size_t freeMemoryIfPossible(size_t bytesToFree);
sugoi@google.com7775fd52012-11-21 15:47:04 +0000221 size_t getBitmapSizeThreshold() const;
222 void setBitmapSizeThreshold(size_t sizeThreshold);
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +0000223 void flushPendingCommands(PlaybackMode);
junov@chromium.org0a67f962012-09-19 22:48:34 +0000224 void skipPendingCommands();
junov@chromium.org88e29142012-08-07 16:48:22 +0000225 void setMaxRecordingStorage(size_t);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000226 void recordedDrawCommand();
junov@chromium.org88e29142012-08-07 16:48:22 +0000227
228 virtual uint32_t getDeviceCapabilities() SK_OVERRIDE;
229 virtual int width() const SK_OVERRIDE;
230 virtual int height() const SK_OVERRIDE;
231 virtual SkGpuRenderTarget* accessRenderTarget() SK_OVERRIDE;
232
233 virtual SkDevice* onCreateCompatibleDevice(SkBitmap::Config config,
234 int width, int height,
235 bool isOpaque,
236 Usage usage) SK_OVERRIDE;
237
238 virtual void writePixels(const SkBitmap& bitmap, int x, int y,
239 SkCanvas::Config8888 config8888) SK_OVERRIDE;
240
241protected:
242 virtual const SkBitmap& onAccessBitmap(SkBitmap*) SK_OVERRIDE;
243 virtual bool onReadPixels(const SkBitmap& bitmap,
244 int x, int y,
245 SkCanvas::Config8888 config8888) SK_OVERRIDE;
246
247 // The following methods are no-ops on a deferred device
248 virtual bool filterTextFlags(const SkPaint& paint, TextFlags*)
249 SK_OVERRIDE
250 {return false;}
junov@chromium.org88e29142012-08-07 16:48:22 +0000251
252 // None of the following drawing methods should ever get called on the
253 // deferred device
254 virtual void clear(SkColor color)
255 {SkASSERT(0);}
256 virtual void drawPaint(const SkDraw&, const SkPaint& paint)
257 {SkASSERT(0);}
258 virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode,
259 size_t count, const SkPoint[],
260 const SkPaint& paint)
261 {SkASSERT(0);}
262 virtual void drawRect(const SkDraw&, const SkRect& r,
263 const SkPaint& paint)
264 {SkASSERT(0);}
265 virtual void drawPath(const SkDraw&, const SkPath& path,
266 const SkPaint& paint,
267 const SkMatrix* prePathMatrix = NULL,
268 bool pathIsMutable = false)
269 {SkASSERT(0);}
270 virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap,
271 const SkIRect* srcRectOrNull,
272 const SkMatrix& matrix, const SkPaint& paint)
273 {SkASSERT(0);}
274 virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap,
275 int x, int y, const SkPaint& paint)
276 {SkASSERT(0);}
277 virtual void drawText(const SkDraw&, const void* text, size_t len,
278 SkScalar x, SkScalar y, const SkPaint& paint)
279 {SkASSERT(0);}
280 virtual void drawPosText(const SkDraw&, const void* text, size_t len,
281 const SkScalar pos[], SkScalar constY,
282 int scalarsPerPos, const SkPaint& paint)
283 {SkASSERT(0);}
284 virtual void drawTextOnPath(const SkDraw&, const void* text,
285 size_t len, const SkPath& path,
286 const SkMatrix* matrix,
287 const SkPaint& paint)
288 {SkASSERT(0);}
289 virtual void drawPosTextOnPath(const SkDraw& draw, const void* text,
290 size_t len, const SkPoint pos[],
291 const SkPaint& paint,
292 const SkPath& path,
293 const SkMatrix* matrix)
294 {SkASSERT(0);}
295 virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode,
296 int vertexCount, const SkPoint verts[],
297 const SkPoint texs[], const SkColor colors[],
298 SkXfermode* xmode, const uint16_t indices[],
299 int indexCount, const SkPaint& paint)
300 {SkASSERT(0);}
301 virtual void drawDevice(const SkDraw&, SkDevice*, int x, int y,
302 const SkPaint&)
303 {SkASSERT(0);}
304private:
305 virtual void flush();
306
junov@chromium.org88e29142012-08-07 16:48:22 +0000307 void beginRecording();
308
309 DeferredPipeController fPipeController;
310 SkGPipeWriter fPipeWriter;
311 SkDevice* fImmediateDevice;
312 SkCanvas* fImmediateCanvas;
313 SkCanvas* fRecordingCanvas;
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000314 SkDeferredCanvas::NotificationClient* fNotificationClient;
junov@chromium.org88e29142012-08-07 16:48:22 +0000315 bool fFreshFrame;
316 size_t fMaxRecordingStorageBytes;
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000317 size_t fPreviousStorageAllocated;
sugoi@google.com7775fd52012-11-21 15:47:04 +0000318 size_t fBitmapSizeThreshold;
junov@chromium.org88e29142012-08-07 16:48:22 +0000319};
320
321DeferredDevice::DeferredDevice(
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000322 SkDevice* immediateDevice, SkDeferredCanvas::NotificationClient* notificationClient) :
junov@chromium.org88e29142012-08-07 16:48:22 +0000323 SkDevice(SkBitmap::kNo_Config, immediateDevice->width(),
324 immediateDevice->height(), immediateDevice->isOpaque())
junov@chromium.orga8db8fe2012-08-15 19:49:22 +0000325 , fRecordingCanvas(NULL)
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000326 , fFreshFrame(true)
sugoi@google.com7775fd52012-11-21 15:47:04 +0000327 , fPreviousStorageAllocated(0)
sugoi@google.com5347de12012-11-21 16:44:45 +0000328 , fBitmapSizeThreshold(kDeferredCanvasBitmapSizeThreshold){
junov@chromium.org88e29142012-08-07 16:48:22 +0000329
330 fMaxRecordingStorageBytes = kDefaultMaxRecordingStorageBytes;
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000331 fNotificationClient = notificationClient;
junov@chromium.org88e29142012-08-07 16:48:22 +0000332 fImmediateDevice = immediateDevice; // ref counted via fImmediateCanvas
333 fImmediateCanvas = SkNEW_ARGS(SkCanvas, (fImmediateDevice));
334 fPipeController.setPlaybackCanvas(fImmediateCanvas);
335 this->beginRecording();
336}
337
338DeferredDevice::~DeferredDevice() {
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +0000339 this->flushPendingCommands(kSilent_PlaybackMode);
junov@chromium.org88e29142012-08-07 16:48:22 +0000340 SkSafeUnref(fImmediateCanvas);
junov@chromium.org88e29142012-08-07 16:48:22 +0000341}
342
343void DeferredDevice::setMaxRecordingStorage(size_t maxStorage) {
344 fMaxRecordingStorageBytes = maxStorage;
345 this->recordingCanvas(); // Accessing the recording canvas applies the new limit.
346}
347
junov@chromium.org88e29142012-08-07 16:48:22 +0000348void DeferredDevice::beginRecording() {
junov@chromium.orga8db8fe2012-08-15 19:49:22 +0000349 SkASSERT(NULL == fRecordingCanvas);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000350 fRecordingCanvas = fPipeWriter.startRecording(&fPipeController, 0,
junov@chromium.orga8db8fe2012-08-15 19:49:22 +0000351 fImmediateDevice->width(), fImmediateDevice->height());
junov@chromium.org88e29142012-08-07 16:48:22 +0000352}
rmistry@google.comd6176b02012-08-23 18:14:13 +0000353
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000354void DeferredDevice::setNotificationClient(
355 SkDeferredCanvas::NotificationClient* notificationClient) {
junov@chromium.org52805482012-08-20 14:25:04 +0000356 fNotificationClient = notificationClient;
junov@chromium.org88e29142012-08-07 16:48:22 +0000357}
358
junov@chromium.org0a67f962012-09-19 22:48:34 +0000359void DeferredDevice::skipPendingCommands() {
junov@chromium.orga38dfb62012-09-20 22:10:33 +0000360 if (!fRecordingCanvas->isDrawingToLayer() && fPipeController.hasPendingCommands()) {
junov@chromium.org88e29142012-08-07 16:48:22 +0000361 fFreshFrame = true;
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +0000362 flushPendingCommands(kSilent_PlaybackMode);
junov@google.com52a00ca2012-10-01 15:27:14 +0000363 if (fNotificationClient) {
364 fNotificationClient->skippedPendingDrawCommands();
365 }
junov@chromium.org88e29142012-08-07 16:48:22 +0000366 }
367}
368
369bool DeferredDevice::isFreshFrame() {
370 bool ret = fFreshFrame;
371 fFreshFrame = false;
372 return ret;
373}
374
junov@chromium.orga38dfb62012-09-20 22:10:33 +0000375bool DeferredDevice::hasPendingCommands() {
376 return fPipeController.hasPendingCommands();
377}
378
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +0000379void DeferredDevice::flushPendingCommands(PlaybackMode playbackMode) {
junov@chromium.orga38dfb62012-09-20 22:10:33 +0000380 if (!fPipeController.hasPendingCommands()) {
junov@chromium.org88e29142012-08-07 16:48:22 +0000381 return;
382 }
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +0000383 if (playbackMode == kNormal_PlaybackMode && fNotificationClient) {
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000384 fNotificationClient->prepareForDraw();
junov@chromium.org88e29142012-08-07 16:48:22 +0000385 }
junov@chromium.org88e29142012-08-07 16:48:22 +0000386 fPipeWriter.flushRecording(true);
junov@chromium.orgd4501a02012-10-30 19:05:17 +0000387 fPipeController.playback(kSilent_PlaybackMode == playbackMode);
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +0000388 if (playbackMode == kNormal_PlaybackMode && fNotificationClient) {
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000389 fNotificationClient->flushedDrawCommands();
390 }
391 fPreviousStorageAllocated = storageAllocatedForRecording();
junov@chromium.org88e29142012-08-07 16:48:22 +0000392}
393
394void DeferredDevice::flush() {
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +0000395 this->flushPendingCommands(kNormal_PlaybackMode);
junov@chromium.org88e29142012-08-07 16:48:22 +0000396 fImmediateCanvas->flush();
397}
398
399size_t DeferredDevice::freeMemoryIfPossible(size_t bytesToFree) {
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000400 size_t val = fPipeWriter.freeMemoryIfPossible(bytesToFree);
401 fPreviousStorageAllocated = storageAllocatedForRecording();
402 return val;
junov@chromium.org88e29142012-08-07 16:48:22 +0000403}
404
sugoi@google.com7775fd52012-11-21 15:47:04 +0000405size_t DeferredDevice::getBitmapSizeThreshold() const {
406 return fBitmapSizeThreshold;
407}
408
409void DeferredDevice::setBitmapSizeThreshold(size_t sizeThreshold) {
410 fBitmapSizeThreshold = sizeThreshold;
411}
412
junov@chromium.org88e29142012-08-07 16:48:22 +0000413size_t DeferredDevice::storageAllocatedForRecording() const {
414 return (fPipeController.storageAllocatedForRecording()
415 + fPipeWriter.storageAllocatedForRecording());
416}
417
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000418void DeferredDevice::recordedDrawCommand() {
junov@chromium.org88e29142012-08-07 16:48:22 +0000419 size_t storageAllocated = this->storageAllocatedForRecording();
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000420
junov@chromium.org88e29142012-08-07 16:48:22 +0000421 if (storageAllocated > fMaxRecordingStorageBytes) {
422 // First, attempt to reduce cache without flushing
423 size_t tryFree = storageAllocated - fMaxRecordingStorageBytes;
424 if (this->freeMemoryIfPossible(tryFree) < tryFree) {
425 // Flush is necessary to free more space.
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +0000426 this->flushPendingCommands(kNormal_PlaybackMode);
junov@chromium.org88e29142012-08-07 16:48:22 +0000427 // Free as much as possible to avoid oscillating around fMaxRecordingStorageBytes
428 // which could cause a high flushing frequency.
bsalomon@google.com100abf42012-09-05 17:40:04 +0000429 this->freeMemoryIfPossible(~0U);
junov@chromium.org88e29142012-08-07 16:48:22 +0000430 }
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000431 storageAllocated = this->storageAllocatedForRecording();
junov@chromium.org88e29142012-08-07 16:48:22 +0000432 }
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000433
rmistry@google.comd6176b02012-08-23 18:14:13 +0000434 if (fNotificationClient &&
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000435 storageAllocated != fPreviousStorageAllocated) {
436 fPreviousStorageAllocated = storageAllocated;
437 fNotificationClient->storageAllocatedForRecordingChanged(storageAllocated);
438 }
439}
440
441SkCanvas* DeferredDevice::recordingCanvas() {
junov@chromium.org88e29142012-08-07 16:48:22 +0000442 return fRecordingCanvas;
443}
444
rmistry@google.comd6176b02012-08-23 18:14:13 +0000445uint32_t DeferredDevice::getDeviceCapabilities() {
junov@chromium.org88e29142012-08-07 16:48:22 +0000446 return fImmediateDevice->getDeviceCapabilities();
447}
448
rmistry@google.comd6176b02012-08-23 18:14:13 +0000449int DeferredDevice::width() const {
junov@chromium.org88e29142012-08-07 16:48:22 +0000450 return fImmediateDevice->width();
451}
452
453int DeferredDevice::height() const {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000454 return fImmediateDevice->height();
junov@chromium.org88e29142012-08-07 16:48:22 +0000455}
456
457SkGpuRenderTarget* DeferredDevice::accessRenderTarget() {
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +0000458 this->flushPendingCommands(kNormal_PlaybackMode);
junov@chromium.org88e29142012-08-07 16:48:22 +0000459 return fImmediateDevice->accessRenderTarget();
460}
461
462void DeferredDevice::writePixels(const SkBitmap& bitmap,
463 int x, int y, SkCanvas::Config8888 config8888) {
464
465 if (x <= 0 && y <= 0 && (x + bitmap.width()) >= width() &&
466 (y + bitmap.height()) >= height()) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000467 this->skipPendingCommands();
junov@chromium.org88e29142012-08-07 16:48:22 +0000468 }
469
470 if (SkBitmap::kARGB_8888_Config == bitmap.config() &&
471 SkCanvas::kNative_Premul_Config8888 != config8888 &&
472 kPMColorAlias != config8888) {
473 //Special case config: no deferral
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +0000474 this->flushPendingCommands(kNormal_PlaybackMode);
junov@chromium.org88e29142012-08-07 16:48:22 +0000475 fImmediateDevice->writePixels(bitmap, x, y, config8888);
476 return;
477 }
478
479 SkPaint paint;
480 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
sugoi@google.com7775fd52012-11-21 15:47:04 +0000481 if (shouldDrawImmediately(&bitmap, NULL, getBitmapSizeThreshold())) {
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +0000482 this->flushPendingCommands(kNormal_PlaybackMode);
junov@chromium.org88e29142012-08-07 16:48:22 +0000483 fImmediateCanvas->drawSprite(bitmap, x, y, &paint);
484 } else {
485 this->recordingCanvas()->drawSprite(bitmap, x, y, &paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000486 this->recordedDrawCommand();
487
junov@chromium.org88e29142012-08-07 16:48:22 +0000488 }
489}
490
491const SkBitmap& DeferredDevice::onAccessBitmap(SkBitmap*) {
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +0000492 this->flushPendingCommands(kNormal_PlaybackMode);
junov@chromium.org88e29142012-08-07 16:48:22 +0000493 return fImmediateDevice->accessBitmap(false);
494}
495
496SkDevice* DeferredDevice::onCreateCompatibleDevice(
497 SkBitmap::Config config, int width, int height, bool isOpaque,
498 Usage usage) {
499
500 // Save layer usage not supported, and not required by SkDeferredCanvas.
501 SkASSERT(usage != kSaveLayer_Usage);
502 // Create a compatible non-deferred device.
503 SkAutoTUnref<SkDevice> compatibleDevice
504 (fImmediateDevice->createCompatibleDevice(config, width, height,
505 isOpaque));
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000506 return SkNEW_ARGS(DeferredDevice, (compatibleDevice, fNotificationClient));
junov@chromium.org88e29142012-08-07 16:48:22 +0000507}
508
509bool DeferredDevice::onReadPixels(
510 const SkBitmap& bitmap, int x, int y, SkCanvas::Config8888 config8888) {
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +0000511 this->flushPendingCommands(kNormal_PlaybackMode);
junov@chromium.org88e29142012-08-07 16:48:22 +0000512 return fImmediateCanvas->readPixels(const_cast<SkBitmap*>(&bitmap),
513 x, y, config8888);
514}
515
sugoi@google.com7775fd52012-11-21 15:47:04 +0000516class AutoImmediateDrawIfNeeded {
517public:
518 AutoImmediateDrawIfNeeded(SkDeferredCanvas& canvas, const SkBitmap* bitmap,
519 const SkPaint* paint) {
520 this->init(canvas, bitmap, paint);
521 }
522
523 AutoImmediateDrawIfNeeded(SkDeferredCanvas& canvas, const SkPaint* paint) {
524 this->init(canvas, NULL, paint);
525 }
526
527 ~AutoImmediateDrawIfNeeded() {
528 if (fCanvas) {
529 fCanvas->setDeferredDrawing(true);
530 }
531 }
532private:
533 void init(SkDeferredCanvas& canvas, const SkBitmap* bitmap, const SkPaint* paint)
534 {
535 DeferredDevice* device = static_cast<DeferredDevice*>(canvas.getDevice());
536 if (canvas.isDeferredDrawing() && (NULL != device) &&
537 shouldDrawImmediately(bitmap, paint, device->getBitmapSizeThreshold())) {
538 canvas.setDeferredDrawing(false);
539 fCanvas = &canvas;
540 } else {
541 fCanvas = NULL;
542 }
543 }
544
545 SkDeferredCanvas* fCanvas;
546};
junov@chromium.org88e29142012-08-07 16:48:22 +0000547
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000548SkDeferredCanvas::SkDeferredCanvas() {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000549 this->init();
junov@google.com4370aed2012-01-18 16:21:08 +0000550}
551
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000552SkDeferredCanvas::SkDeferredCanvas(SkDevice* device) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000553 this->init();
554 this->setDevice(device);
junov@google.com4370aed2012-01-18 16:21:08 +0000555}
556
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000557void SkDeferredCanvas::init() {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000558 fDeferredDrawing = true; // On by default
junov@google.com4370aed2012-01-18 16:21:08 +0000559}
560
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000561void SkDeferredCanvas::setMaxRecordingStorage(size_t maxStorage) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000562 this->validate();
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000563 this->getDeferredDevice()->setMaxRecordingStorage(maxStorage);
564}
565
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000566size_t SkDeferredCanvas::storageAllocatedForRecording() const {
567 return this->getDeferredDevice()->storageAllocatedForRecording();
568}
569
570size_t SkDeferredCanvas::freeMemoryIfPossible(size_t bytesToFree) {
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000571 return this->getDeferredDevice()->freeMemoryIfPossible(bytesToFree);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000572}
573
sugoi@google.com7775fd52012-11-21 15:47:04 +0000574void SkDeferredCanvas::setBitmapSizeThreshold(size_t sizeThreshold) {
575 DeferredDevice* deferredDevice = this->getDeferredDevice();
576 SkASSERT(deferredDevice);
577 deferredDevice->setBitmapSizeThreshold(sizeThreshold);
578}
579
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000580void SkDeferredCanvas::recordedDrawCommand() {
581 if (fDeferredDrawing) {
582 this->getDeferredDevice()->recordedDrawCommand();
583 }
584}
585
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000586void SkDeferredCanvas::validate() const {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000587 SkASSERT(this->getDevice());
junov@google.com4370aed2012-01-18 16:21:08 +0000588}
589
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000590SkCanvas* SkDeferredCanvas::drawingCanvas() const {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000591 this->validate();
592 return fDeferredDrawing ? this->getDeferredDevice()->recordingCanvas() :
593 this->getDeferredDevice()->immediateCanvas();
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000594}
595
junov@chromium.org88e29142012-08-07 16:48:22 +0000596SkCanvas* SkDeferredCanvas::immediateCanvas() const {
597 this->validate();
598 return this->getDeferredDevice()->immediateCanvas();
599}
600
601DeferredDevice* SkDeferredCanvas::getDeferredDevice() const {
602 return static_cast<DeferredDevice*>(this->getDevice());
junov@google.com4370aed2012-01-18 16:21:08 +0000603}
604
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000605void SkDeferredCanvas::setDeferredDrawing(bool val) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000606 this->validate(); // Must set device before calling this method
junov@google.com4370aed2012-01-18 16:21:08 +0000607 if (val != fDeferredDrawing) {
608 if (fDeferredDrawing) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000609 // Going live.
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +0000610 this->getDeferredDevice()->flushPendingCommands(kNormal_PlaybackMode);
junov@google.com4370aed2012-01-18 16:21:08 +0000611 }
612 fDeferredDrawing = val;
613 }
614}
615
junov@chromium.org88e29142012-08-07 16:48:22 +0000616bool SkDeferredCanvas::isDeferredDrawing() const {
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +0000617 return fDeferredDrawing;
618}
619
junov@chromium.org88e29142012-08-07 16:48:22 +0000620bool SkDeferredCanvas::isFreshFrame() const {
621 return this->getDeferredDevice()->isFreshFrame();
622}
623
junov@chromium.orga38dfb62012-09-20 22:10:33 +0000624bool SkDeferredCanvas::hasPendingCommands() const {
625 return this->getDeferredDevice()->hasPendingCommands();
626}
627
junov@chromium.orgfb103892012-09-20 19:35:43 +0000628void SkDeferredCanvas::silentFlush() {
629 if (fDeferredDrawing) {
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +0000630 this->getDeferredDevice()->flushPendingCommands(kSilent_PlaybackMode);
junov@chromium.orgfb103892012-09-20 19:35:43 +0000631 }
632}
633
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000634SkDeferredCanvas::~SkDeferredCanvas() {
junov@google.com4370aed2012-01-18 16:21:08 +0000635}
636
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000637SkDevice* SkDeferredCanvas::setDevice(SkDevice* device) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000638 this->INHERITED::setDevice(SkNEW_ARGS(DeferredDevice, (device)))->unref();
junov@google.com4370aed2012-01-18 16:21:08 +0000639 return device;
640}
641
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000642SkDeferredCanvas::NotificationClient* SkDeferredCanvas::setNotificationClient(
643 NotificationClient* notificationClient) {
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000644
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000645 DeferredDevice* deferredDevice = this->getDeferredDevice();
junov@google.com4370aed2012-01-18 16:21:08 +0000646 SkASSERT(deferredDevice);
647 if (deferredDevice) {
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000648 deferredDevice->setNotificationClient(notificationClient);
junov@google.com4370aed2012-01-18 16:21:08 +0000649 }
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000650 return notificationClient;
junov@google.com4370aed2012-01-18 16:21:08 +0000651}
652
653bool SkDeferredCanvas::isFullFrame(const SkRect* rect,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000654 const SkPaint* paint) const {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000655 SkCanvas* canvas = this->drawingCanvas();
656 SkISize canvasSize = this->getDeviceSize();
junov@google.com4370aed2012-01-18 16:21:08 +0000657 if (rect) {
658 if (!canvas->getTotalMatrix().rectStaysRect()) {
659 return false; // conservative
660 }
661
662 SkRect transformedRect;
663 canvas->getTotalMatrix().mapRect(&transformedRect, *rect);
664
665 if (paint) {
666 SkPaint::Style paintStyle = paint->getStyle();
rmistry@google.comd6176b02012-08-23 18:14:13 +0000667 if (!(paintStyle == SkPaint::kFill_Style ||
junov@google.com4370aed2012-01-18 16:21:08 +0000668 paintStyle == SkPaint::kStrokeAndFill_Style)) {
669 return false;
670 }
671 if (paint->getMaskFilter() || paint->getLooper()
672 || paint->getPathEffect() || paint->getImageFilter()) {
673 return false; // conservative
674 }
675 }
676
677 // The following test holds with AA enabled, and is conservative
678 // by a 0.5 pixel margin with AA disabled
rmistry@google.comd6176b02012-08-23 18:14:13 +0000679 if (transformedRect.fLeft > SkIntToScalar(0) ||
680 transformedRect.fTop > SkIntToScalar(0) ||
junov@chromium.orgb1e218e2012-02-13 22:27:58 +0000681 transformedRect.fRight < SkIntToScalar(canvasSize.fWidth) ||
682 transformedRect.fBottom < SkIntToScalar(canvasSize.fHeight)) {
junov@google.com4370aed2012-01-18 16:21:08 +0000683 return false;
684 }
685 }
686
687 switch (canvas->getClipType()) {
688 case SkCanvas::kRect_ClipType :
689 {
690 SkIRect bounds;
691 canvas->getClipDeviceBounds(&bounds);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000692 if (bounds.fLeft > 0 || bounds.fTop > 0 ||
693 bounds.fRight < canvasSize.fWidth ||
junov@google.com4370aed2012-01-18 16:21:08 +0000694 bounds.fBottom < canvasSize.fHeight)
695 return false;
696 }
697 break;
698 case SkCanvas::kComplex_ClipType :
699 return false; // conservative
700 case SkCanvas::kEmpty_ClipType:
701 default:
702 break;
703 };
704
705 return true;
706}
707
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000708int SkDeferredCanvas::save(SaveFlags flags) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000709 this->drawingCanvas()->save(flags);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000710 int val = this->INHERITED::save(flags);
711 this->recordedDrawCommand();
712
713 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000714}
715
716int SkDeferredCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000717 SaveFlags flags) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000718 this->drawingCanvas()->saveLayer(bounds, paint, flags);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000719 int count = this->INHERITED::save(flags);
720 this->clipRectBounds(bounds, flags, NULL);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000721 this->recordedDrawCommand();
722
junov@chromium.orga907ac32012-02-24 21:54:07 +0000723 return count;
junov@google.com4370aed2012-01-18 16:21:08 +0000724}
725
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000726void SkDeferredCanvas::restore() {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000727 this->drawingCanvas()->restore();
junov@chromium.orga907ac32012-02-24 21:54:07 +0000728 this->INHERITED::restore();
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000729 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000730}
731
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000732bool SkDeferredCanvas::isDrawingToLayer() const {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000733 return this->drawingCanvas()->isDrawingToLayer();
junov@google.com4370aed2012-01-18 16:21:08 +0000734}
735
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000736bool SkDeferredCanvas::translate(SkScalar dx, SkScalar dy) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000737 this->drawingCanvas()->translate(dx, dy);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000738 bool val = this->INHERITED::translate(dx, dy);
739 this->recordedDrawCommand();
740 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000741}
742
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000743bool SkDeferredCanvas::scale(SkScalar sx, SkScalar sy) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000744 this->drawingCanvas()->scale(sx, sy);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000745 bool val = this->INHERITED::scale(sx, sy);
746 this->recordedDrawCommand();
747 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000748}
749
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000750bool SkDeferredCanvas::rotate(SkScalar degrees) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000751 this->drawingCanvas()->rotate(degrees);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000752 bool val = this->INHERITED::rotate(degrees);
753 this->recordedDrawCommand();
754 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000755}
756
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000757bool SkDeferredCanvas::skew(SkScalar sx, SkScalar sy) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000758 this->drawingCanvas()->skew(sx, sy);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000759 bool val = this->INHERITED::skew(sx, sy);
760 this->recordedDrawCommand();
761 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000762}
763
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000764bool SkDeferredCanvas::concat(const SkMatrix& matrix) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000765 this->drawingCanvas()->concat(matrix);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000766 bool val = this->INHERITED::concat(matrix);
767 this->recordedDrawCommand();
768 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000769}
770
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000771void SkDeferredCanvas::setMatrix(const SkMatrix& matrix) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000772 this->drawingCanvas()->setMatrix(matrix);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000773 this->INHERITED::setMatrix(matrix);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000774 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000775}
776
777bool SkDeferredCanvas::clipRect(const SkRect& rect,
778 SkRegion::Op op,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000779 bool doAntiAlias) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000780 this->drawingCanvas()->clipRect(rect, op, doAntiAlias);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000781 bool val = this->INHERITED::clipRect(rect, op, doAntiAlias);
782 this->recordedDrawCommand();
783 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000784}
785
reed@google.com4ed0fb72012-12-12 20:48:18 +0000786bool SkDeferredCanvas::clipRRect(const SkRRect& rrect,
787 SkRegion::Op op,
788 bool doAntiAlias) {
789 this->drawingCanvas()->clipRRect(rrect, op, doAntiAlias);
790 bool val = this->INHERITED::clipRRect(rrect, op, doAntiAlias);
791 this->recordedDrawCommand();
792 return val;
793}
794
junov@google.com4370aed2012-01-18 16:21:08 +0000795bool SkDeferredCanvas::clipPath(const SkPath& path,
796 SkRegion::Op op,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000797 bool doAntiAlias) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000798 this->drawingCanvas()->clipPath(path, op, doAntiAlias);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000799 bool val = this->INHERITED::clipPath(path, op, doAntiAlias);
800 this->recordedDrawCommand();
801 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000802}
803
804bool SkDeferredCanvas::clipRegion(const SkRegion& deviceRgn,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000805 SkRegion::Op op) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000806 this->drawingCanvas()->clipRegion(deviceRgn, op);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000807 bool val = this->INHERITED::clipRegion(deviceRgn, op);
808 this->recordedDrawCommand();
809 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000810}
811
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000812void SkDeferredCanvas::clear(SkColor color) {
junov@google.com4370aed2012-01-18 16:21:08 +0000813 // purge pending commands
814 if (fDeferredDrawing) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000815 this->getDeferredDevice()->skipPendingCommands();
junov@google.com4370aed2012-01-18 16:21:08 +0000816 }
817
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000818 this->drawingCanvas()->clear(color);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000819 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000820}
821
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000822void SkDeferredCanvas::drawPaint(const SkPaint& paint) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000823 if (fDeferredDrawing && this->isFullFrame(NULL, &paint) &&
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000824 isPaintOpaque(&paint)) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000825 this->getDeferredDevice()->skipPendingCommands();
junov@google.com4370aed2012-01-18 16:21:08 +0000826 }
junov@chromium.org10f7f972012-07-31 21:01:51 +0000827 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000828 this->drawingCanvas()->drawPaint(paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000829 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000830}
831
832void SkDeferredCanvas::drawPoints(PointMode mode, size_t count,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000833 const SkPoint pts[], const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000834 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000835 this->drawingCanvas()->drawPoints(mode, count, pts, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000836 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000837}
838
reed@google.com4ed0fb72012-12-12 20:48:18 +0000839void SkDeferredCanvas::drawOval(const SkRect& rect, const SkPaint& paint) {
840 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
841 this->drawingCanvas()->drawOval(rect, paint);
842 this->recordedDrawCommand();
843}
844
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000845void SkDeferredCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000846 if (fDeferredDrawing && this->isFullFrame(&rect, &paint) &&
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000847 isPaintOpaque(&paint)) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000848 this->getDeferredDevice()->skipPendingCommands();
junov@google.com4370aed2012-01-18 16:21:08 +0000849 }
reed@google.com4ed0fb72012-12-12 20:48:18 +0000850
junov@chromium.org10f7f972012-07-31 21:01:51 +0000851 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000852 this->drawingCanvas()->drawRect(rect, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000853 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000854}
855
reed@google.com4ed0fb72012-12-12 20:48:18 +0000856void SkDeferredCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
857 if (rrect.isRect()) {
858 this->SkDeferredCanvas::drawRect(rrect.getBounds(), paint);
859 } else if (rrect.isOval()) {
860 this->SkDeferredCanvas::drawOval(rrect.getBounds(), paint);
861 } else {
862 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
863 this->drawingCanvas()->drawRRect(rrect, paint);
864 this->recordedDrawCommand();
865 }
866}
867
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000868void SkDeferredCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000869 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000870 this->drawingCanvas()->drawPath(path, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000871 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000872}
873
874void SkDeferredCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000875 SkScalar top, const SkPaint* paint) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000876 SkRect bitmapRect = SkRect::MakeXYWH(left, top,
877 SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
rmistry@google.comd6176b02012-08-23 18:14:13 +0000878 if (fDeferredDrawing &&
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000879 this->isFullFrame(&bitmapRect, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000880 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000881 this->getDeferredDevice()->skipPendingCommands();
junov@google.com4370aed2012-01-18 16:21:08 +0000882 }
883
junov@chromium.org10f7f972012-07-31 21:01:51 +0000884 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000885 this->drawingCanvas()->drawBitmap(bitmap, left, top, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000886 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000887}
888
reed@google.com71121732012-09-18 15:14:33 +0000889void SkDeferredCanvas::drawBitmapRectToRect(const SkBitmap& bitmap,
890 const SkRect* src,
891 const SkRect& dst,
892 const SkPaint* paint) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000893 if (fDeferredDrawing &&
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000894 this->isFullFrame(&dst, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000895 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000896 this->getDeferredDevice()->skipPendingCommands();
junov@google.com4370aed2012-01-18 16:21:08 +0000897 }
898
junov@chromium.org10f7f972012-07-31 21:01:51 +0000899 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
reed@google.com71121732012-09-18 15:14:33 +0000900 this->drawingCanvas()->drawBitmapRectToRect(bitmap, src, dst, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000901 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000902}
903
904
905void SkDeferredCanvas::drawBitmapMatrix(const SkBitmap& bitmap,
906 const SkMatrix& m,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000907 const SkPaint* paint) {
junov@google.com4370aed2012-01-18 16:21:08 +0000908 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
909 // covers canvas entirely and transformed bitmap covers canvas entirely
junov@chromium.org10f7f972012-07-31 21:01:51 +0000910 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000911 this->drawingCanvas()->drawBitmapMatrix(bitmap, m, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000912 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000913}
914
915void SkDeferredCanvas::drawBitmapNine(const SkBitmap& bitmap,
916 const SkIRect& center, const SkRect& dst,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000917 const SkPaint* paint) {
junov@google.com4370aed2012-01-18 16:21:08 +0000918 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
919 // covers canvas entirely and dst covers canvas entirely
junov@chromium.org10f7f972012-07-31 21:01:51 +0000920 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000921 this->drawingCanvas()->drawBitmapNine(bitmap, center, dst, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000922 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000923}
924
925void SkDeferredCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000926 const SkPaint* paint) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000927 SkRect bitmapRect = SkRect::MakeXYWH(
928 SkIntToScalar(left),
rmistry@google.comd6176b02012-08-23 18:14:13 +0000929 SkIntToScalar(top),
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000930 SkIntToScalar(bitmap.width()),
931 SkIntToScalar(bitmap.height()));
rmistry@google.comd6176b02012-08-23 18:14:13 +0000932 if (fDeferredDrawing &&
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000933 this->isFullFrame(&bitmapRect, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000934 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000935 this->getDeferredDevice()->skipPendingCommands();
junov@google.com4370aed2012-01-18 16:21:08 +0000936 }
937
junov@chromium.org10f7f972012-07-31 21:01:51 +0000938 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000939 this->drawingCanvas()->drawSprite(bitmap, left, top, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000940 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000941}
942
943void SkDeferredCanvas::drawText(const void* text, size_t byteLength,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000944 SkScalar x, SkScalar y, const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000945 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000946 this->drawingCanvas()->drawText(text, byteLength, x, y, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000947 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000948}
949
950void SkDeferredCanvas::drawPosText(const void* text, size_t byteLength,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000951 const SkPoint pos[], const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000952 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000953 this->drawingCanvas()->drawPosText(text, byteLength, pos, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000954 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000955}
956
957void SkDeferredCanvas::drawPosTextH(const void* text, size_t byteLength,
958 const SkScalar xpos[], SkScalar constY,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000959 const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000960 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000961 this->drawingCanvas()->drawPosTextH(text, byteLength, xpos, constY, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000962 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000963}
964
965void SkDeferredCanvas::drawTextOnPath(const void* text, size_t byteLength,
966 const SkPath& path,
967 const SkMatrix* matrix,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000968 const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000969 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000970 this->drawingCanvas()->drawTextOnPath(text, byteLength, path, matrix, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000971 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000972}
973
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000974void SkDeferredCanvas::drawPicture(SkPicture& picture) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000975 this->drawingCanvas()->drawPicture(picture);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000976 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000977}
978
979void SkDeferredCanvas::drawVertices(VertexMode vmode, int vertexCount,
980 const SkPoint vertices[],
981 const SkPoint texs[],
982 const SkColor colors[], SkXfermode* xmode,
983 const uint16_t indices[], int indexCount,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000984 const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000985 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000986 this->drawingCanvas()->drawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
987 indices, indexCount, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000988 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000989}
990
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000991SkBounder* SkDeferredCanvas::setBounder(SkBounder* bounder) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000992 this->drawingCanvas()->setBounder(bounder);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000993 this->INHERITED::setBounder(bounder);
994 this->recordedDrawCommand();
995 return bounder;
junov@google.com4370aed2012-01-18 16:21:08 +0000996}
997
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000998SkDrawFilter* SkDeferredCanvas::setDrawFilter(SkDrawFilter* filter) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000999 this->drawingCanvas()->setDrawFilter(filter);
junov@chromium.org9ed02b92012-08-14 13:36:26 +00001000 this->INHERITED::setDrawFilter(filter);
1001 this->recordedDrawCommand();
rmistry@google.comd6176b02012-08-23 18:14:13 +00001002 return filter;
junov@google.com4370aed2012-01-18 16:21:08 +00001003}
1004
1005SkCanvas* SkDeferredCanvas::canvasForDrawIter() {
junov@chromium.org9060c9b2012-08-07 15:14:01 +00001006 return this->drawingCanvas();
junov@google.com4370aed2012-01-18 16:21:08 +00001007}