blob: 3c6dc2c7efc1c02227e1aea3f003bb0316909457 [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,
reed@google.com140d7282013-01-07 20:25:04 +000023 kDeferredCanvasBitmapSizeThreshold = ~0U, // 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) :
bungeman@google.com532470f2013-01-22 19:25:14 +0000323 SkDevice(SkBitmap::kNo_Config,
324 immediateDevice->width(), immediateDevice->height(),
325 immediateDevice->isOpaque(),
326 immediateDevice->getDeviceProperties())
junov@chromium.orga8db8fe2012-08-15 19:49:22 +0000327 , fRecordingCanvas(NULL)
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000328 , fFreshFrame(true)
sugoi@google.com7775fd52012-11-21 15:47:04 +0000329 , fPreviousStorageAllocated(0)
sugoi@google.com5347de12012-11-21 16:44:45 +0000330 , fBitmapSizeThreshold(kDeferredCanvasBitmapSizeThreshold){
junov@chromium.org88e29142012-08-07 16:48:22 +0000331
332 fMaxRecordingStorageBytes = kDefaultMaxRecordingStorageBytes;
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000333 fNotificationClient = notificationClient;
junov@chromium.org88e29142012-08-07 16:48:22 +0000334 fImmediateDevice = immediateDevice; // ref counted via fImmediateCanvas
335 fImmediateCanvas = SkNEW_ARGS(SkCanvas, (fImmediateDevice));
336 fPipeController.setPlaybackCanvas(fImmediateCanvas);
337 this->beginRecording();
338}
339
340DeferredDevice::~DeferredDevice() {
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +0000341 this->flushPendingCommands(kSilent_PlaybackMode);
junov@chromium.org88e29142012-08-07 16:48:22 +0000342 SkSafeUnref(fImmediateCanvas);
junov@chromium.org88e29142012-08-07 16:48:22 +0000343}
344
345void DeferredDevice::setMaxRecordingStorage(size_t maxStorage) {
346 fMaxRecordingStorageBytes = maxStorage;
347 this->recordingCanvas(); // Accessing the recording canvas applies the new limit.
348}
349
junov@chromium.org88e29142012-08-07 16:48:22 +0000350void DeferredDevice::beginRecording() {
junov@chromium.orga8db8fe2012-08-15 19:49:22 +0000351 SkASSERT(NULL == fRecordingCanvas);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000352 fRecordingCanvas = fPipeWriter.startRecording(&fPipeController, 0,
junov@chromium.orga8db8fe2012-08-15 19:49:22 +0000353 fImmediateDevice->width(), fImmediateDevice->height());
junov@chromium.org88e29142012-08-07 16:48:22 +0000354}
rmistry@google.comd6176b02012-08-23 18:14:13 +0000355
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000356void DeferredDevice::setNotificationClient(
357 SkDeferredCanvas::NotificationClient* notificationClient) {
junov@chromium.org52805482012-08-20 14:25:04 +0000358 fNotificationClient = notificationClient;
junov@chromium.org88e29142012-08-07 16:48:22 +0000359}
360
junov@chromium.org0a67f962012-09-19 22:48:34 +0000361void DeferredDevice::skipPendingCommands() {
junov@chromium.orga38dfb62012-09-20 22:10:33 +0000362 if (!fRecordingCanvas->isDrawingToLayer() && fPipeController.hasPendingCommands()) {
junov@chromium.org88e29142012-08-07 16:48:22 +0000363 fFreshFrame = true;
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +0000364 flushPendingCommands(kSilent_PlaybackMode);
junov@google.com52a00ca2012-10-01 15:27:14 +0000365 if (fNotificationClient) {
366 fNotificationClient->skippedPendingDrawCommands();
367 }
junov@chromium.org88e29142012-08-07 16:48:22 +0000368 }
369}
370
371bool DeferredDevice::isFreshFrame() {
372 bool ret = fFreshFrame;
373 fFreshFrame = false;
374 return ret;
375}
376
junov@chromium.orga38dfb62012-09-20 22:10:33 +0000377bool DeferredDevice::hasPendingCommands() {
378 return fPipeController.hasPendingCommands();
379}
380
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +0000381void DeferredDevice::flushPendingCommands(PlaybackMode playbackMode) {
junov@chromium.orga38dfb62012-09-20 22:10:33 +0000382 if (!fPipeController.hasPendingCommands()) {
junov@chromium.org88e29142012-08-07 16:48:22 +0000383 return;
384 }
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +0000385 if (playbackMode == kNormal_PlaybackMode && fNotificationClient) {
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000386 fNotificationClient->prepareForDraw();
junov@chromium.org88e29142012-08-07 16:48:22 +0000387 }
junov@chromium.org88e29142012-08-07 16:48:22 +0000388 fPipeWriter.flushRecording(true);
junov@chromium.orgd4501a02012-10-30 19:05:17 +0000389 fPipeController.playback(kSilent_PlaybackMode == playbackMode);
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +0000390 if (playbackMode == kNormal_PlaybackMode && fNotificationClient) {
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000391 fNotificationClient->flushedDrawCommands();
392 }
393 fPreviousStorageAllocated = storageAllocatedForRecording();
junov@chromium.org88e29142012-08-07 16:48:22 +0000394}
395
396void DeferredDevice::flush() {
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +0000397 this->flushPendingCommands(kNormal_PlaybackMode);
junov@chromium.org88e29142012-08-07 16:48:22 +0000398 fImmediateCanvas->flush();
399}
400
401size_t DeferredDevice::freeMemoryIfPossible(size_t bytesToFree) {
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000402 size_t val = fPipeWriter.freeMemoryIfPossible(bytesToFree);
403 fPreviousStorageAllocated = storageAllocatedForRecording();
404 return val;
junov@chromium.org88e29142012-08-07 16:48:22 +0000405}
406
sugoi@google.com7775fd52012-11-21 15:47:04 +0000407size_t DeferredDevice::getBitmapSizeThreshold() const {
408 return fBitmapSizeThreshold;
409}
410
411void DeferredDevice::setBitmapSizeThreshold(size_t sizeThreshold) {
412 fBitmapSizeThreshold = sizeThreshold;
413}
414
junov@chromium.org88e29142012-08-07 16:48:22 +0000415size_t DeferredDevice::storageAllocatedForRecording() const {
416 return (fPipeController.storageAllocatedForRecording()
417 + fPipeWriter.storageAllocatedForRecording());
418}
419
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000420void DeferredDevice::recordedDrawCommand() {
junov@chromium.org88e29142012-08-07 16:48:22 +0000421 size_t storageAllocated = this->storageAllocatedForRecording();
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000422
junov@chromium.org88e29142012-08-07 16:48:22 +0000423 if (storageAllocated > fMaxRecordingStorageBytes) {
424 // First, attempt to reduce cache without flushing
425 size_t tryFree = storageAllocated - fMaxRecordingStorageBytes;
426 if (this->freeMemoryIfPossible(tryFree) < tryFree) {
427 // Flush is necessary to free more space.
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +0000428 this->flushPendingCommands(kNormal_PlaybackMode);
junov@chromium.org88e29142012-08-07 16:48:22 +0000429 // Free as much as possible to avoid oscillating around fMaxRecordingStorageBytes
430 // which could cause a high flushing frequency.
bsalomon@google.com100abf42012-09-05 17:40:04 +0000431 this->freeMemoryIfPossible(~0U);
junov@chromium.org88e29142012-08-07 16:48:22 +0000432 }
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000433 storageAllocated = this->storageAllocatedForRecording();
junov@chromium.org88e29142012-08-07 16:48:22 +0000434 }
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000435
rmistry@google.comd6176b02012-08-23 18:14:13 +0000436 if (fNotificationClient &&
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000437 storageAllocated != fPreviousStorageAllocated) {
438 fPreviousStorageAllocated = storageAllocated;
439 fNotificationClient->storageAllocatedForRecordingChanged(storageAllocated);
440 }
441}
442
443SkCanvas* DeferredDevice::recordingCanvas() {
junov@chromium.org88e29142012-08-07 16:48:22 +0000444 return fRecordingCanvas;
445}
446
rmistry@google.comd6176b02012-08-23 18:14:13 +0000447uint32_t DeferredDevice::getDeviceCapabilities() {
junov@chromium.org88e29142012-08-07 16:48:22 +0000448 return fImmediateDevice->getDeviceCapabilities();
449}
450
rmistry@google.comd6176b02012-08-23 18:14:13 +0000451int DeferredDevice::width() const {
junov@chromium.org88e29142012-08-07 16:48:22 +0000452 return fImmediateDevice->width();
453}
454
455int DeferredDevice::height() const {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000456 return fImmediateDevice->height();
junov@chromium.org88e29142012-08-07 16:48:22 +0000457}
458
459SkGpuRenderTarget* DeferredDevice::accessRenderTarget() {
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +0000460 this->flushPendingCommands(kNormal_PlaybackMode);
junov@chromium.org88e29142012-08-07 16:48:22 +0000461 return fImmediateDevice->accessRenderTarget();
462}
463
464void DeferredDevice::writePixels(const SkBitmap& bitmap,
465 int x, int y, SkCanvas::Config8888 config8888) {
466
467 if (x <= 0 && y <= 0 && (x + bitmap.width()) >= width() &&
468 (y + bitmap.height()) >= height()) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000469 this->skipPendingCommands();
junov@chromium.org88e29142012-08-07 16:48:22 +0000470 }
471
472 if (SkBitmap::kARGB_8888_Config == bitmap.config() &&
473 SkCanvas::kNative_Premul_Config8888 != config8888 &&
474 kPMColorAlias != config8888) {
475 //Special case config: no deferral
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +0000476 this->flushPendingCommands(kNormal_PlaybackMode);
junov@chromium.org88e29142012-08-07 16:48:22 +0000477 fImmediateDevice->writePixels(bitmap, x, y, config8888);
478 return;
479 }
480
481 SkPaint paint;
482 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
sugoi@google.com7775fd52012-11-21 15:47:04 +0000483 if (shouldDrawImmediately(&bitmap, NULL, getBitmapSizeThreshold())) {
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +0000484 this->flushPendingCommands(kNormal_PlaybackMode);
junov@chromium.org88e29142012-08-07 16:48:22 +0000485 fImmediateCanvas->drawSprite(bitmap, x, y, &paint);
486 } else {
487 this->recordingCanvas()->drawSprite(bitmap, x, y, &paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000488 this->recordedDrawCommand();
489
junov@chromium.org88e29142012-08-07 16:48:22 +0000490 }
491}
492
493const SkBitmap& DeferredDevice::onAccessBitmap(SkBitmap*) {
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +0000494 this->flushPendingCommands(kNormal_PlaybackMode);
junov@chromium.org88e29142012-08-07 16:48:22 +0000495 return fImmediateDevice->accessBitmap(false);
496}
497
498SkDevice* DeferredDevice::onCreateCompatibleDevice(
499 SkBitmap::Config config, int width, int height, bool isOpaque,
500 Usage usage) {
501
502 // Save layer usage not supported, and not required by SkDeferredCanvas.
503 SkASSERT(usage != kSaveLayer_Usage);
504 // Create a compatible non-deferred device.
505 SkAutoTUnref<SkDevice> compatibleDevice
506 (fImmediateDevice->createCompatibleDevice(config, width, height,
507 isOpaque));
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000508 return SkNEW_ARGS(DeferredDevice, (compatibleDevice, fNotificationClient));
junov@chromium.org88e29142012-08-07 16:48:22 +0000509}
510
511bool DeferredDevice::onReadPixels(
512 const SkBitmap& bitmap, int x, int y, SkCanvas::Config8888 config8888) {
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +0000513 this->flushPendingCommands(kNormal_PlaybackMode);
junov@chromium.org88e29142012-08-07 16:48:22 +0000514 return fImmediateCanvas->readPixels(const_cast<SkBitmap*>(&bitmap),
515 x, y, config8888);
516}
517
sugoi@google.com7775fd52012-11-21 15:47:04 +0000518class AutoImmediateDrawIfNeeded {
519public:
520 AutoImmediateDrawIfNeeded(SkDeferredCanvas& canvas, const SkBitmap* bitmap,
521 const SkPaint* paint) {
522 this->init(canvas, bitmap, paint);
523 }
524
525 AutoImmediateDrawIfNeeded(SkDeferredCanvas& canvas, const SkPaint* paint) {
526 this->init(canvas, NULL, paint);
527 }
528
529 ~AutoImmediateDrawIfNeeded() {
530 if (fCanvas) {
531 fCanvas->setDeferredDrawing(true);
532 }
533 }
534private:
535 void init(SkDeferredCanvas& canvas, const SkBitmap* bitmap, const SkPaint* paint)
536 {
537 DeferredDevice* device = static_cast<DeferredDevice*>(canvas.getDevice());
538 if (canvas.isDeferredDrawing() && (NULL != device) &&
539 shouldDrawImmediately(bitmap, paint, device->getBitmapSizeThreshold())) {
540 canvas.setDeferredDrawing(false);
541 fCanvas = &canvas;
542 } else {
543 fCanvas = NULL;
544 }
545 }
546
547 SkDeferredCanvas* fCanvas;
548};
junov@chromium.org88e29142012-08-07 16:48:22 +0000549
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000550SkDeferredCanvas::SkDeferredCanvas() {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000551 this->init();
junov@google.com4370aed2012-01-18 16:21:08 +0000552}
553
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000554SkDeferredCanvas::SkDeferredCanvas(SkDevice* device) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000555 this->init();
556 this->setDevice(device);
junov@google.com4370aed2012-01-18 16:21:08 +0000557}
558
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000559void SkDeferredCanvas::init() {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000560 fDeferredDrawing = true; // On by default
junov@google.com4370aed2012-01-18 16:21:08 +0000561}
562
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000563void SkDeferredCanvas::setMaxRecordingStorage(size_t maxStorage) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000564 this->validate();
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000565 this->getDeferredDevice()->setMaxRecordingStorage(maxStorage);
566}
567
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000568size_t SkDeferredCanvas::storageAllocatedForRecording() const {
569 return this->getDeferredDevice()->storageAllocatedForRecording();
570}
571
572size_t SkDeferredCanvas::freeMemoryIfPossible(size_t bytesToFree) {
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000573 return this->getDeferredDevice()->freeMemoryIfPossible(bytesToFree);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000574}
575
sugoi@google.com7775fd52012-11-21 15:47:04 +0000576void SkDeferredCanvas::setBitmapSizeThreshold(size_t sizeThreshold) {
577 DeferredDevice* deferredDevice = this->getDeferredDevice();
578 SkASSERT(deferredDevice);
579 deferredDevice->setBitmapSizeThreshold(sizeThreshold);
580}
581
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000582void SkDeferredCanvas::recordedDrawCommand() {
583 if (fDeferredDrawing) {
584 this->getDeferredDevice()->recordedDrawCommand();
585 }
586}
587
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000588void SkDeferredCanvas::validate() const {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000589 SkASSERT(this->getDevice());
junov@google.com4370aed2012-01-18 16:21:08 +0000590}
591
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000592SkCanvas* SkDeferredCanvas::drawingCanvas() const {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000593 this->validate();
594 return fDeferredDrawing ? this->getDeferredDevice()->recordingCanvas() :
595 this->getDeferredDevice()->immediateCanvas();
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000596}
597
junov@chromium.org88e29142012-08-07 16:48:22 +0000598SkCanvas* SkDeferredCanvas::immediateCanvas() const {
599 this->validate();
600 return this->getDeferredDevice()->immediateCanvas();
601}
602
603DeferredDevice* SkDeferredCanvas::getDeferredDevice() const {
604 return static_cast<DeferredDevice*>(this->getDevice());
junov@google.com4370aed2012-01-18 16:21:08 +0000605}
606
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000607void SkDeferredCanvas::setDeferredDrawing(bool val) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000608 this->validate(); // Must set device before calling this method
junov@google.com4370aed2012-01-18 16:21:08 +0000609 if (val != fDeferredDrawing) {
610 if (fDeferredDrawing) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000611 // Going live.
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +0000612 this->getDeferredDevice()->flushPendingCommands(kNormal_PlaybackMode);
junov@google.com4370aed2012-01-18 16:21:08 +0000613 }
614 fDeferredDrawing = val;
615 }
616}
617
junov@chromium.org88e29142012-08-07 16:48:22 +0000618bool SkDeferredCanvas::isDeferredDrawing() const {
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +0000619 return fDeferredDrawing;
620}
621
junov@chromium.org88e29142012-08-07 16:48:22 +0000622bool SkDeferredCanvas::isFreshFrame() const {
623 return this->getDeferredDevice()->isFreshFrame();
624}
625
junov@chromium.orga38dfb62012-09-20 22:10:33 +0000626bool SkDeferredCanvas::hasPendingCommands() const {
627 return this->getDeferredDevice()->hasPendingCommands();
628}
629
junov@chromium.orgfb103892012-09-20 19:35:43 +0000630void SkDeferredCanvas::silentFlush() {
631 if (fDeferredDrawing) {
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +0000632 this->getDeferredDevice()->flushPendingCommands(kSilent_PlaybackMode);
junov@chromium.orgfb103892012-09-20 19:35:43 +0000633 }
634}
635
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000636SkDeferredCanvas::~SkDeferredCanvas() {
junov@google.com4370aed2012-01-18 16:21:08 +0000637}
638
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000639SkDevice* SkDeferredCanvas::setDevice(SkDevice* device) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000640 this->INHERITED::setDevice(SkNEW_ARGS(DeferredDevice, (device)))->unref();
junov@google.com4370aed2012-01-18 16:21:08 +0000641 return device;
642}
643
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000644SkDeferredCanvas::NotificationClient* SkDeferredCanvas::setNotificationClient(
645 NotificationClient* notificationClient) {
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000646
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000647 DeferredDevice* deferredDevice = this->getDeferredDevice();
junov@google.com4370aed2012-01-18 16:21:08 +0000648 SkASSERT(deferredDevice);
649 if (deferredDevice) {
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000650 deferredDevice->setNotificationClient(notificationClient);
junov@google.com4370aed2012-01-18 16:21:08 +0000651 }
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000652 return notificationClient;
junov@google.com4370aed2012-01-18 16:21:08 +0000653}
654
655bool SkDeferredCanvas::isFullFrame(const SkRect* rect,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000656 const SkPaint* paint) const {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000657 SkCanvas* canvas = this->drawingCanvas();
658 SkISize canvasSize = this->getDeviceSize();
junov@google.com4370aed2012-01-18 16:21:08 +0000659 if (rect) {
660 if (!canvas->getTotalMatrix().rectStaysRect()) {
661 return false; // conservative
662 }
663
664 SkRect transformedRect;
665 canvas->getTotalMatrix().mapRect(&transformedRect, *rect);
666
667 if (paint) {
668 SkPaint::Style paintStyle = paint->getStyle();
rmistry@google.comd6176b02012-08-23 18:14:13 +0000669 if (!(paintStyle == SkPaint::kFill_Style ||
junov@google.com4370aed2012-01-18 16:21:08 +0000670 paintStyle == SkPaint::kStrokeAndFill_Style)) {
671 return false;
672 }
673 if (paint->getMaskFilter() || paint->getLooper()
674 || paint->getPathEffect() || paint->getImageFilter()) {
675 return false; // conservative
676 }
677 }
678
679 // The following test holds with AA enabled, and is conservative
680 // by a 0.5 pixel margin with AA disabled
rmistry@google.comd6176b02012-08-23 18:14:13 +0000681 if (transformedRect.fLeft > SkIntToScalar(0) ||
682 transformedRect.fTop > SkIntToScalar(0) ||
junov@chromium.orgb1e218e2012-02-13 22:27:58 +0000683 transformedRect.fRight < SkIntToScalar(canvasSize.fWidth) ||
684 transformedRect.fBottom < SkIntToScalar(canvasSize.fHeight)) {
junov@google.com4370aed2012-01-18 16:21:08 +0000685 return false;
686 }
687 }
688
junov@chromium.org8f0ca062012-12-13 16:30:39 +0000689 return this->getClipStack()->quickContains(SkRect::MakeXYWH(0, 0,
690 SkIntToScalar(canvasSize.fWidth), SkIntToScalar(canvasSize.fHeight)));
junov@google.com4370aed2012-01-18 16:21:08 +0000691}
692
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000693int SkDeferredCanvas::save(SaveFlags flags) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000694 this->drawingCanvas()->save(flags);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000695 int val = this->INHERITED::save(flags);
696 this->recordedDrawCommand();
697
698 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000699}
700
701int SkDeferredCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000702 SaveFlags flags) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000703 this->drawingCanvas()->saveLayer(bounds, paint, flags);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000704 int count = this->INHERITED::save(flags);
705 this->clipRectBounds(bounds, flags, NULL);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000706 this->recordedDrawCommand();
707
junov@chromium.orga907ac32012-02-24 21:54:07 +0000708 return count;
junov@google.com4370aed2012-01-18 16:21:08 +0000709}
710
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000711void SkDeferredCanvas::restore() {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000712 this->drawingCanvas()->restore();
junov@chromium.orga907ac32012-02-24 21:54:07 +0000713 this->INHERITED::restore();
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000714 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000715}
716
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000717bool SkDeferredCanvas::isDrawingToLayer() const {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000718 return this->drawingCanvas()->isDrawingToLayer();
junov@google.com4370aed2012-01-18 16:21:08 +0000719}
720
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000721bool SkDeferredCanvas::translate(SkScalar dx, SkScalar dy) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000722 this->drawingCanvas()->translate(dx, dy);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000723 bool val = this->INHERITED::translate(dx, dy);
724 this->recordedDrawCommand();
725 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000726}
727
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000728bool SkDeferredCanvas::scale(SkScalar sx, SkScalar sy) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000729 this->drawingCanvas()->scale(sx, sy);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000730 bool val = this->INHERITED::scale(sx, sy);
731 this->recordedDrawCommand();
732 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000733}
734
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000735bool SkDeferredCanvas::rotate(SkScalar degrees) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000736 this->drawingCanvas()->rotate(degrees);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000737 bool val = this->INHERITED::rotate(degrees);
738 this->recordedDrawCommand();
739 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000740}
741
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000742bool SkDeferredCanvas::skew(SkScalar sx, SkScalar sy) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000743 this->drawingCanvas()->skew(sx, sy);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000744 bool val = this->INHERITED::skew(sx, sy);
745 this->recordedDrawCommand();
746 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000747}
748
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000749bool SkDeferredCanvas::concat(const SkMatrix& matrix) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000750 this->drawingCanvas()->concat(matrix);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000751 bool val = this->INHERITED::concat(matrix);
752 this->recordedDrawCommand();
753 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000754}
755
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000756void SkDeferredCanvas::setMatrix(const SkMatrix& matrix) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000757 this->drawingCanvas()->setMatrix(matrix);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000758 this->INHERITED::setMatrix(matrix);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000759 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000760}
761
762bool SkDeferredCanvas::clipRect(const SkRect& rect,
763 SkRegion::Op op,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000764 bool doAntiAlias) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000765 this->drawingCanvas()->clipRect(rect, op, doAntiAlias);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000766 bool val = this->INHERITED::clipRect(rect, op, doAntiAlias);
767 this->recordedDrawCommand();
768 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000769}
770
reed@google.com4ed0fb72012-12-12 20:48:18 +0000771bool SkDeferredCanvas::clipRRect(const SkRRect& rrect,
772 SkRegion::Op op,
773 bool doAntiAlias) {
774 this->drawingCanvas()->clipRRect(rrect, op, doAntiAlias);
775 bool val = this->INHERITED::clipRRect(rrect, op, doAntiAlias);
776 this->recordedDrawCommand();
777 return val;
778}
779
junov@google.com4370aed2012-01-18 16:21:08 +0000780bool SkDeferredCanvas::clipPath(const SkPath& path,
781 SkRegion::Op op,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000782 bool doAntiAlias) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000783 this->drawingCanvas()->clipPath(path, op, doAntiAlias);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000784 bool val = this->INHERITED::clipPath(path, op, doAntiAlias);
785 this->recordedDrawCommand();
786 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000787}
788
789bool SkDeferredCanvas::clipRegion(const SkRegion& deviceRgn,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000790 SkRegion::Op op) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000791 this->drawingCanvas()->clipRegion(deviceRgn, op);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000792 bool val = this->INHERITED::clipRegion(deviceRgn, op);
793 this->recordedDrawCommand();
794 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000795}
796
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000797void SkDeferredCanvas::clear(SkColor color) {
junov@google.com4370aed2012-01-18 16:21:08 +0000798 // purge pending commands
799 if (fDeferredDrawing) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000800 this->getDeferredDevice()->skipPendingCommands();
junov@google.com4370aed2012-01-18 16:21:08 +0000801 }
802
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000803 this->drawingCanvas()->clear(color);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000804 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000805}
806
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000807void SkDeferredCanvas::drawPaint(const SkPaint& paint) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000808 if (fDeferredDrawing && this->isFullFrame(NULL, &paint) &&
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000809 isPaintOpaque(&paint)) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000810 this->getDeferredDevice()->skipPendingCommands();
junov@google.com4370aed2012-01-18 16:21:08 +0000811 }
junov@chromium.org10f7f972012-07-31 21:01:51 +0000812 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000813 this->drawingCanvas()->drawPaint(paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000814 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000815}
816
817void SkDeferredCanvas::drawPoints(PointMode mode, size_t count,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000818 const SkPoint pts[], const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000819 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000820 this->drawingCanvas()->drawPoints(mode, count, pts, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000821 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000822}
823
reed@google.com4ed0fb72012-12-12 20:48:18 +0000824void SkDeferredCanvas::drawOval(const SkRect& rect, const SkPaint& paint) {
825 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
826 this->drawingCanvas()->drawOval(rect, paint);
827 this->recordedDrawCommand();
828}
829
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000830void SkDeferredCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000831 if (fDeferredDrawing && this->isFullFrame(&rect, &paint) &&
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000832 isPaintOpaque(&paint)) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000833 this->getDeferredDevice()->skipPendingCommands();
junov@google.com4370aed2012-01-18 16:21:08 +0000834 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000835
junov@chromium.org10f7f972012-07-31 21:01:51 +0000836 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000837 this->drawingCanvas()->drawRect(rect, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000838 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000839}
840
reed@google.com4ed0fb72012-12-12 20:48:18 +0000841void SkDeferredCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
842 if (rrect.isRect()) {
843 this->SkDeferredCanvas::drawRect(rrect.getBounds(), paint);
844 } else if (rrect.isOval()) {
845 this->SkDeferredCanvas::drawOval(rrect.getBounds(), paint);
846 } else {
847 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
848 this->drawingCanvas()->drawRRect(rrect, paint);
849 this->recordedDrawCommand();
850 }
851}
852
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000853void SkDeferredCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000854 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000855 this->drawingCanvas()->drawPath(path, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000856 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000857}
858
859void SkDeferredCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000860 SkScalar top, const SkPaint* paint) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000861 SkRect bitmapRect = SkRect::MakeXYWH(left, top,
862 SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
rmistry@google.comd6176b02012-08-23 18:14:13 +0000863 if (fDeferredDrawing &&
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000864 this->isFullFrame(&bitmapRect, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000865 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000866 this->getDeferredDevice()->skipPendingCommands();
junov@google.com4370aed2012-01-18 16:21:08 +0000867 }
868
junov@chromium.org10f7f972012-07-31 21:01:51 +0000869 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000870 this->drawingCanvas()->drawBitmap(bitmap, left, top, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000871 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000872}
873
reed@google.com71121732012-09-18 15:14:33 +0000874void SkDeferredCanvas::drawBitmapRectToRect(const SkBitmap& bitmap,
875 const SkRect* src,
876 const SkRect& dst,
877 const SkPaint* paint) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000878 if (fDeferredDrawing &&
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000879 this->isFullFrame(&dst, 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);
reed@google.com71121732012-09-18 15:14:33 +0000885 this->drawingCanvas()->drawBitmapRectToRect(bitmap, src, dst, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000886 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000887}
888
889
890void SkDeferredCanvas::drawBitmapMatrix(const SkBitmap& bitmap,
891 const SkMatrix& m,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000892 const SkPaint* paint) {
junov@google.com4370aed2012-01-18 16:21:08 +0000893 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
894 // covers canvas entirely and transformed bitmap covers canvas entirely
junov@chromium.org10f7f972012-07-31 21:01:51 +0000895 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000896 this->drawingCanvas()->drawBitmapMatrix(bitmap, m, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000897 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000898}
899
900void SkDeferredCanvas::drawBitmapNine(const SkBitmap& bitmap,
901 const SkIRect& center, const SkRect& dst,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000902 const SkPaint* paint) {
junov@google.com4370aed2012-01-18 16:21:08 +0000903 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
904 // covers canvas entirely and dst covers canvas entirely
junov@chromium.org10f7f972012-07-31 21:01:51 +0000905 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000906 this->drawingCanvas()->drawBitmapNine(bitmap, center, dst, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000907 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000908}
909
910void SkDeferredCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000911 const SkPaint* paint) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000912 SkRect bitmapRect = SkRect::MakeXYWH(
913 SkIntToScalar(left),
rmistry@google.comd6176b02012-08-23 18:14:13 +0000914 SkIntToScalar(top),
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000915 SkIntToScalar(bitmap.width()),
916 SkIntToScalar(bitmap.height()));
rmistry@google.comd6176b02012-08-23 18:14:13 +0000917 if (fDeferredDrawing &&
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000918 this->isFullFrame(&bitmapRect, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000919 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000920 this->getDeferredDevice()->skipPendingCommands();
junov@google.com4370aed2012-01-18 16:21:08 +0000921 }
922
junov@chromium.org10f7f972012-07-31 21:01:51 +0000923 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000924 this->drawingCanvas()->drawSprite(bitmap, left, top, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000925 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000926}
927
928void SkDeferredCanvas::drawText(const void* text, size_t byteLength,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000929 SkScalar x, SkScalar y, const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000930 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000931 this->drawingCanvas()->drawText(text, byteLength, x, y, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000932 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000933}
934
935void SkDeferredCanvas::drawPosText(const void* text, size_t byteLength,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000936 const SkPoint pos[], const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000937 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000938 this->drawingCanvas()->drawPosText(text, byteLength, pos, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000939 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000940}
941
942void SkDeferredCanvas::drawPosTextH(const void* text, size_t byteLength,
943 const SkScalar xpos[], SkScalar constY,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000944 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()->drawPosTextH(text, byteLength, xpos, constY, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000947 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000948}
949
950void SkDeferredCanvas::drawTextOnPath(const void* text, size_t byteLength,
951 const SkPath& path,
952 const SkMatrix* matrix,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000953 const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000954 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000955 this->drawingCanvas()->drawTextOnPath(text, byteLength, path, matrix, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000956 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000957}
958
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000959void SkDeferredCanvas::drawPicture(SkPicture& picture) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000960 this->drawingCanvas()->drawPicture(picture);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000961 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000962}
963
964void SkDeferredCanvas::drawVertices(VertexMode vmode, int vertexCount,
965 const SkPoint vertices[],
966 const SkPoint texs[],
967 const SkColor colors[], SkXfermode* xmode,
968 const uint16_t indices[], int indexCount,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000969 const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000970 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000971 this->drawingCanvas()->drawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
972 indices, indexCount, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000973 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000974}
975
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000976SkBounder* SkDeferredCanvas::setBounder(SkBounder* bounder) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000977 this->drawingCanvas()->setBounder(bounder);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000978 this->INHERITED::setBounder(bounder);
979 this->recordedDrawCommand();
980 return bounder;
junov@google.com4370aed2012-01-18 16:21:08 +0000981}
982
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000983SkDrawFilter* SkDeferredCanvas::setDrawFilter(SkDrawFilter* filter) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000984 this->drawingCanvas()->setDrawFilter(filter);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000985 this->INHERITED::setDrawFilter(filter);
986 this->recordedDrawCommand();
rmistry@google.comd6176b02012-08-23 18:14:13 +0000987 return filter;
junov@google.com4370aed2012-01-18 16:21:08 +0000988}
989
990SkCanvas* SkDeferredCanvas::canvasForDrawIter() {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000991 return this->drawingCanvas();
junov@google.com4370aed2012-01-18 16:21:08 +0000992}