blob: ffc935d5de6045bfa03eef334353421626db5f1d [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"
17#include "SkShader.h"
junov@google.com4370aed2012-01-18 16:21:08 +000018
sugoi@google.com7775fd52012-11-21 15:47:04 +000019#ifndef SK_DEFERRED_CANVAS_BITMAP_SIZE_THRESHOLD
20#define SK_DEFERRED_CANVAS_BITMAP_SIZE_THRESHOLD ~0 // Disables this feature
21#endif
22
junov@chromium.orgbfeddae2012-07-23 13:35:14 +000023enum {
24 // Deferred canvas will auto-flush when recording reaches this limit
25 kDefaultMaxRecordingStorageBytes = 64*1024*1024,
26};
27
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +000028enum PlaybackMode {
29 kNormal_PlaybackMode,
30 kSilent_PlaybackMode,
31};
32
junov@google.com4370aed2012-01-18 16:21:08 +000033namespace {
sugoi@google.com7775fd52012-11-21 15:47:04 +000034bool shouldDrawImmediately(const SkBitmap* bitmap, const SkPaint* paint,
35 size_t bitmapSizeThreshold) {
36 if (bitmap && ((bitmap->getTexture() && !bitmap->isImmutable()) ||
37 (bitmap->getSize() > bitmapSizeThreshold))) {
junov@chromium.org10f7f972012-07-31 21:01:51 +000038 return true;
39 }
40 if (paint) {
41 SkShader* shader = paint->getShader();
42 // Here we detect the case where the shader is an SkBitmapProcShader
43 // with a gpu texture attached. Checking this without RTTI
44 // requires making the assumption that only gradient shaders
45 // and SkBitmapProcShader implement asABitmap(). The following
46 // code may need to be revised if that assumption is ever broken.
47 if (shader && !shader->asAGradient(NULL)) {
48 SkBitmap bm;
rmistry@google.comd6176b02012-08-23 18:14:13 +000049 if (shader->asABitmap(&bm, NULL, NULL) &&
junov@chromium.org10f7f972012-07-31 21:01:51 +000050 NULL != bm.getTexture()) {
51 return true;
52 }
53 }
54 }
55 return false;
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +000056}
57}
58
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +000059namespace {
junov@google.com4370aed2012-01-18 16:21:08 +000060
rmistry@google.comd6176b02012-08-23 18:14:13 +000061bool isPaintOpaque(const SkPaint* paint,
junov@chromium.orgc16ca922012-02-24 22:06:27 +000062 const SkBitmap* bmpReplacesShader = NULL) {
junov@google.com4370aed2012-01-18 16:21:08 +000063 // TODO: SkXfermode should have a virtual isOpaque method, which would
64 // make it possible to test modes that do not have a Coeff representation.
junov@chromium.org87f982c2012-02-23 21:34:34 +000065
66 if (!paint) {
67 return bmpReplacesShader ? bmpReplacesShader->isOpaque() : true;
68 }
69
junov@google.com4370aed2012-01-18 16:21:08 +000070 SkXfermode::Coeff srcCoeff, dstCoeff;
junov@chromium.org87f982c2012-02-23 21:34:34 +000071 if (SkXfermode::AsCoeff(paint->getXfermode(), &srcCoeff, &dstCoeff)){
junov@chromium.org8cef67a2012-10-11 20:19:15 +000072 if (SkXfermode::kDA_Coeff == srcCoeff || SkXfermode::kDC_Coeff == srcCoeff ||
73 SkXfermode::kIDA_Coeff == srcCoeff || SkXfermode::kIDC_Coeff == srcCoeff) {
74 return false;
75 }
junov@google.com4370aed2012-01-18 16:21:08 +000076 switch (dstCoeff) {
77 case SkXfermode::kZero_Coeff:
78 return true;
79 case SkXfermode::kISA_Coeff:
junov@chromium.org87f982c2012-02-23 21:34:34 +000080 if (paint->getAlpha() != 255) {
junov@google.com4370aed2012-01-18 16:21:08 +000081 break;
82 }
83 if (bmpReplacesShader) {
84 if (!bmpReplacesShader->isOpaque()) {
85 break;
86 }
junov@chromium.org87f982c2012-02-23 21:34:34 +000087 } else if (paint->getShader() && !paint->getShader()->isOpaque()) {
junov@google.com4370aed2012-01-18 16:21:08 +000088 break;
89 }
rmistry@google.comd6176b02012-08-23 18:14:13 +000090 if (paint->getColorFilter() &&
junov@chromium.orgc16ca922012-02-24 22:06:27 +000091 ((paint->getColorFilter()->getFlags() &
junov@google.com4370aed2012-01-18 16:21:08 +000092 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
93 break;
94 }
95 return true;
96 case SkXfermode::kSA_Coeff:
junov@chromium.org87f982c2012-02-23 21:34:34 +000097 if (paint->getAlpha() != 0) {
junov@google.com4370aed2012-01-18 16:21:08 +000098 break;
99 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000100 if (paint->getColorFilter() &&
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000101 ((paint->getColorFilter()->getFlags() &
junov@google.com4370aed2012-01-18 16:21:08 +0000102 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
103 break;
104 }
105 return true;
106 case SkXfermode::kSC_Coeff:
junov@chromium.org87f982c2012-02-23 21:34:34 +0000107 if (paint->getColor() != 0) { // all components must be 0
junov@google.com4370aed2012-01-18 16:21:08 +0000108 break;
109 }
junov@chromium.org87f982c2012-02-23 21:34:34 +0000110 if (bmpReplacesShader || paint->getShader()) {
junov@google.com4370aed2012-01-18 16:21:08 +0000111 break;
112 }
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000113 if (paint->getColorFilter() && (
114 (paint->getColorFilter()->getFlags() &
junov@google.com4370aed2012-01-18 16:21:08 +0000115 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
116 break;
117 }
118 return true;
119 default:
120 break;
121 }
122 }
123 return false;
124}
125
126} // unnamed namespace
127
junov@chromium.org88e29142012-08-07 16:48:22 +0000128//-----------------------------------------------------------------------------
129// DeferredPipeController
130//-----------------------------------------------------------------------------
131
132class DeferredPipeController : public SkGPipeController {
133public:
134 DeferredPipeController();
135 void setPlaybackCanvas(SkCanvas*);
136 virtual ~DeferredPipeController();
137 virtual void* requestBlock(size_t minRequest, size_t* actual) SK_OVERRIDE;
138 virtual void notifyWritten(size_t bytes) SK_OVERRIDE;
junov@chromium.orgfb103892012-09-20 19:35:43 +0000139 void playback(bool silent);
junov@chromium.orga38dfb62012-09-20 22:10:33 +0000140 bool hasPendingCommands() const { return fAllocator.blockCount() != 0; }
junov@chromium.org88e29142012-08-07 16:48:22 +0000141 size_t storageAllocatedForRecording() const { return fAllocator.totalCapacity(); }
142private:
143 enum {
144 kMinBlockSize = 4096
145 };
146 struct PipeBlock {
147 PipeBlock(void* block, size_t size) { fBlock = block, fSize = size; }
148 void* fBlock;
149 size_t fSize;
150 };
151 void* fBlock;
152 size_t fBytesWritten;
153 SkChunkAlloc fAllocator;
154 SkTDArray<PipeBlock> fBlockList;
155 SkGPipeReader fReader;
156};
157
158DeferredPipeController::DeferredPipeController() :
159 fAllocator(kMinBlockSize) {
160 fBlock = NULL;
161 fBytesWritten = 0;
162}
163
164DeferredPipeController::~DeferredPipeController() {
165 fAllocator.reset();
166}
167
168void DeferredPipeController::setPlaybackCanvas(SkCanvas* canvas) {
169 fReader.setCanvas(canvas);
170}
171
172void* DeferredPipeController::requestBlock(size_t minRequest, size_t *actual) {
173 if (fBlock) {
174 // Save the previous block for later
175 PipeBlock previousBloc(fBlock, fBytesWritten);
176 fBlockList.push(previousBloc);
177 }
178 int32_t blockSize = SkMax32(minRequest, kMinBlockSize);
179 fBlock = fAllocator.allocThrow(blockSize);
180 fBytesWritten = 0;
181 *actual = blockSize;
182 return fBlock;
183}
184
185void DeferredPipeController::notifyWritten(size_t bytes) {
186 fBytesWritten += bytes;
187}
188
junov@chromium.orgfb103892012-09-20 19:35:43 +0000189void DeferredPipeController::playback(bool silent) {
190 uint32_t flags = silent ? SkGPipeReader::kSilent_PlaybackFlag : 0;
junov@chromium.org88e29142012-08-07 16:48:22 +0000191 for (int currentBlock = 0; currentBlock < fBlockList.count(); currentBlock++ ) {
junov@chromium.orgfb103892012-09-20 19:35:43 +0000192 fReader.playback(fBlockList[currentBlock].fBlock, fBlockList[currentBlock].fSize,
193 flags);
junov@chromium.org88e29142012-08-07 16:48:22 +0000194 }
195 fBlockList.reset();
196
197 if (fBlock) {
junov@chromium.orgfb103892012-09-20 19:35:43 +0000198 fReader.playback(fBlock, fBytesWritten, flags);
junov@chromium.org88e29142012-08-07 16:48:22 +0000199 fBlock = NULL;
200 }
201
202 // Release all allocated blocks
203 fAllocator.reset();
204}
205
junov@chromium.org88e29142012-08-07 16:48:22 +0000206//-----------------------------------------------------------------------------
207// DeferredDevice
208//-----------------------------------------------------------------------------
junov@chromium.org88e29142012-08-07 16:48:22 +0000209class DeferredDevice : public SkDevice {
210public:
211 DeferredDevice(SkDevice* immediateDevice,
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000212 SkDeferredCanvas::NotificationClient* notificationClient = NULL);
junov@chromium.org88e29142012-08-07 16:48:22 +0000213 ~DeferredDevice();
214
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000215 void setNotificationClient(SkDeferredCanvas::NotificationClient* notificationClient);
junov@chromium.org88e29142012-08-07 16:48:22 +0000216 SkCanvas* recordingCanvas();
217 SkCanvas* immediateCanvas() const {return fImmediateCanvas;}
218 SkDevice* immediateDevice() const {return fImmediateDevice;}
219 bool isFreshFrame();
junov@chromium.orga38dfb62012-09-20 22:10:33 +0000220 bool hasPendingCommands();
junov@chromium.org88e29142012-08-07 16:48:22 +0000221 size_t storageAllocatedForRecording() const;
222 size_t freeMemoryIfPossible(size_t bytesToFree);
sugoi@google.com7775fd52012-11-21 15:47:04 +0000223 size_t getBitmapSizeThreshold() const;
224 void setBitmapSizeThreshold(size_t sizeThreshold);
junov@chromium.orgeeaf47f2012-09-20 20:42:44 +0000225 void flushPendingCommands(PlaybackMode);
junov@chromium.org0a67f962012-09-19 22:48:34 +0000226 void skipPendingCommands();
junov@chromium.org88e29142012-08-07 16:48:22 +0000227 void setMaxRecordingStorage(size_t);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000228 void recordedDrawCommand();
junov@chromium.org88e29142012-08-07 16:48:22 +0000229
230 virtual uint32_t getDeviceCapabilities() SK_OVERRIDE;
231 virtual int width() const SK_OVERRIDE;
232 virtual int height() const SK_OVERRIDE;
233 virtual SkGpuRenderTarget* accessRenderTarget() SK_OVERRIDE;
234
235 virtual SkDevice* onCreateCompatibleDevice(SkBitmap::Config config,
236 int width, int height,
237 bool isOpaque,
238 Usage usage) SK_OVERRIDE;
239
240 virtual void writePixels(const SkBitmap& bitmap, int x, int y,
241 SkCanvas::Config8888 config8888) SK_OVERRIDE;
242
243protected:
244 virtual const SkBitmap& onAccessBitmap(SkBitmap*) SK_OVERRIDE;
245 virtual bool onReadPixels(const SkBitmap& bitmap,
246 int x, int y,
247 SkCanvas::Config8888 config8888) SK_OVERRIDE;
248
249 // The following methods are no-ops on a deferred device
250 virtual bool filterTextFlags(const SkPaint& paint, TextFlags*)
251 SK_OVERRIDE
252 {return false;}
junov@chromium.org88e29142012-08-07 16:48:22 +0000253
254 // None of the following drawing methods should ever get called on the
255 // deferred device
256 virtual void clear(SkColor color)
257 {SkASSERT(0);}
258 virtual void drawPaint(const SkDraw&, const SkPaint& paint)
259 {SkASSERT(0);}
260 virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode,
261 size_t count, const SkPoint[],
262 const SkPaint& paint)
263 {SkASSERT(0);}
264 virtual void drawRect(const SkDraw&, const SkRect& r,
265 const SkPaint& paint)
266 {SkASSERT(0);}
267 virtual void drawPath(const SkDraw&, const SkPath& path,
268 const SkPaint& paint,
269 const SkMatrix* prePathMatrix = NULL,
270 bool pathIsMutable = false)
271 {SkASSERT(0);}
272 virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap,
273 const SkIRect* srcRectOrNull,
274 const SkMatrix& matrix, const SkPaint& paint)
275 {SkASSERT(0);}
276 virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap,
277 int x, int y, const SkPaint& paint)
278 {SkASSERT(0);}
279 virtual void drawText(const SkDraw&, const void* text, size_t len,
280 SkScalar x, SkScalar y, const SkPaint& paint)
281 {SkASSERT(0);}
282 virtual void drawPosText(const SkDraw&, const void* text, size_t len,
283 const SkScalar pos[], SkScalar constY,
284 int scalarsPerPos, const SkPaint& paint)
285 {SkASSERT(0);}
286 virtual void drawTextOnPath(const SkDraw&, const void* text,
287 size_t len, const SkPath& path,
288 const SkMatrix* matrix,
289 const SkPaint& paint)
290 {SkASSERT(0);}
291 virtual void drawPosTextOnPath(const SkDraw& draw, const void* text,
292 size_t len, const SkPoint pos[],
293 const SkPaint& paint,
294 const SkPath& path,
295 const SkMatrix* matrix)
296 {SkASSERT(0);}
297 virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode,
298 int vertexCount, const SkPoint verts[],
299 const SkPoint texs[], const SkColor colors[],
300 SkXfermode* xmode, const uint16_t indices[],
301 int indexCount, const SkPaint& paint)
302 {SkASSERT(0);}
303 virtual void drawDevice(const SkDraw&, SkDevice*, int x, int y,
304 const SkPaint&)
305 {SkASSERT(0);}
306private:
307 virtual void flush();
308
junov@chromium.org88e29142012-08-07 16:48:22 +0000309 void beginRecording();
310
311 DeferredPipeController fPipeController;
312 SkGPipeWriter fPipeWriter;
313 SkDevice* fImmediateDevice;
314 SkCanvas* fImmediateCanvas;
315 SkCanvas* fRecordingCanvas;
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000316 SkDeferredCanvas::NotificationClient* fNotificationClient;
junov@chromium.org88e29142012-08-07 16:48:22 +0000317 bool fFreshFrame;
318 size_t fMaxRecordingStorageBytes;
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000319 size_t fPreviousStorageAllocated;
sugoi@google.com7775fd52012-11-21 15:47:04 +0000320 size_t fBitmapSizeThreshold;
junov@chromium.org88e29142012-08-07 16:48:22 +0000321};
322
323DeferredDevice::DeferredDevice(
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000324 SkDevice* immediateDevice, SkDeferredCanvas::NotificationClient* notificationClient) :
junov@chromium.org88e29142012-08-07 16:48:22 +0000325 SkDevice(SkBitmap::kNo_Config, immediateDevice->width(),
326 immediateDevice->height(), immediateDevice->isOpaque())
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)
330 , fBitmapSizeThreshold(SK_DEFERRED_CANVAS_BITMAP_SIZE_THRESHOLD){
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
689 switch (canvas->getClipType()) {
690 case SkCanvas::kRect_ClipType :
691 {
692 SkIRect bounds;
693 canvas->getClipDeviceBounds(&bounds);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000694 if (bounds.fLeft > 0 || bounds.fTop > 0 ||
695 bounds.fRight < canvasSize.fWidth ||
junov@google.com4370aed2012-01-18 16:21:08 +0000696 bounds.fBottom < canvasSize.fHeight)
697 return false;
698 }
699 break;
700 case SkCanvas::kComplex_ClipType :
701 return false; // conservative
702 case SkCanvas::kEmpty_ClipType:
703 default:
704 break;
705 };
706
707 return true;
708}
709
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000710int SkDeferredCanvas::save(SaveFlags flags) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000711 this->drawingCanvas()->save(flags);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000712 int val = this->INHERITED::save(flags);
713 this->recordedDrawCommand();
714
715 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000716}
717
718int SkDeferredCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000719 SaveFlags flags) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000720 this->drawingCanvas()->saveLayer(bounds, paint, flags);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000721 int count = this->INHERITED::save(flags);
722 this->clipRectBounds(bounds, flags, NULL);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000723 this->recordedDrawCommand();
724
junov@chromium.orga907ac32012-02-24 21:54:07 +0000725 return count;
junov@google.com4370aed2012-01-18 16:21:08 +0000726}
727
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000728void SkDeferredCanvas::restore() {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000729 this->drawingCanvas()->restore();
junov@chromium.orga907ac32012-02-24 21:54:07 +0000730 this->INHERITED::restore();
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000731 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000732}
733
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000734bool SkDeferredCanvas::isDrawingToLayer() const {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000735 return this->drawingCanvas()->isDrawingToLayer();
junov@google.com4370aed2012-01-18 16:21:08 +0000736}
737
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000738bool SkDeferredCanvas::translate(SkScalar dx, SkScalar dy) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000739 this->drawingCanvas()->translate(dx, dy);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000740 bool val = this->INHERITED::translate(dx, dy);
741 this->recordedDrawCommand();
742 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000743}
744
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000745bool SkDeferredCanvas::scale(SkScalar sx, SkScalar sy) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000746 this->drawingCanvas()->scale(sx, sy);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000747 bool val = this->INHERITED::scale(sx, sy);
748 this->recordedDrawCommand();
749 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000750}
751
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000752bool SkDeferredCanvas::rotate(SkScalar degrees) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000753 this->drawingCanvas()->rotate(degrees);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000754 bool val = this->INHERITED::rotate(degrees);
755 this->recordedDrawCommand();
756 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000757}
758
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000759bool SkDeferredCanvas::skew(SkScalar sx, SkScalar sy) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000760 this->drawingCanvas()->skew(sx, sy);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000761 bool val = this->INHERITED::skew(sx, sy);
762 this->recordedDrawCommand();
763 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000764}
765
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000766bool SkDeferredCanvas::concat(const SkMatrix& matrix) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000767 this->drawingCanvas()->concat(matrix);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000768 bool val = this->INHERITED::concat(matrix);
769 this->recordedDrawCommand();
770 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000771}
772
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000773void SkDeferredCanvas::setMatrix(const SkMatrix& matrix) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000774 this->drawingCanvas()->setMatrix(matrix);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000775 this->INHERITED::setMatrix(matrix);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000776 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000777}
778
779bool SkDeferredCanvas::clipRect(const SkRect& rect,
780 SkRegion::Op op,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000781 bool doAntiAlias) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000782 this->drawingCanvas()->clipRect(rect, op, doAntiAlias);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000783 bool val = this->INHERITED::clipRect(rect, op, doAntiAlias);
784 this->recordedDrawCommand();
785 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000786}
787
788bool SkDeferredCanvas::clipPath(const SkPath& path,
789 SkRegion::Op op,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000790 bool doAntiAlias) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000791 this->drawingCanvas()->clipPath(path, op, doAntiAlias);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000792 bool val = this->INHERITED::clipPath(path, op, doAntiAlias);
793 this->recordedDrawCommand();
794 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000795}
796
797bool SkDeferredCanvas::clipRegion(const SkRegion& deviceRgn,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000798 SkRegion::Op op) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000799 this->drawingCanvas()->clipRegion(deviceRgn, op);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000800 bool val = this->INHERITED::clipRegion(deviceRgn, op);
801 this->recordedDrawCommand();
802 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000803}
804
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000805void SkDeferredCanvas::clear(SkColor color) {
junov@google.com4370aed2012-01-18 16:21:08 +0000806 // purge pending commands
807 if (fDeferredDrawing) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000808 this->getDeferredDevice()->skipPendingCommands();
junov@google.com4370aed2012-01-18 16:21:08 +0000809 }
810
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000811 this->drawingCanvas()->clear(color);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000812 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000813}
814
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000815void SkDeferredCanvas::drawPaint(const SkPaint& paint) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000816 if (fDeferredDrawing && this->isFullFrame(NULL, &paint) &&
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000817 isPaintOpaque(&paint)) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000818 this->getDeferredDevice()->skipPendingCommands();
junov@google.com4370aed2012-01-18 16:21:08 +0000819 }
junov@chromium.org10f7f972012-07-31 21:01:51 +0000820 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000821 this->drawingCanvas()->drawPaint(paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000822 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000823}
824
825void SkDeferredCanvas::drawPoints(PointMode mode, size_t count,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000826 const SkPoint pts[], const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000827 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000828 this->drawingCanvas()->drawPoints(mode, count, pts, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000829 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000830}
831
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000832void SkDeferredCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000833 if (fDeferredDrawing && this->isFullFrame(&rect, &paint) &&
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000834 isPaintOpaque(&paint)) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000835 this->getDeferredDevice()->skipPendingCommands();
junov@google.com4370aed2012-01-18 16:21:08 +0000836 }
837
junov@chromium.org10f7f972012-07-31 21:01:51 +0000838 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000839 this->drawingCanvas()->drawRect(rect, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000840 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000841}
842
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000843void SkDeferredCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000844 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000845 this->drawingCanvas()->drawPath(path, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000846 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000847}
848
849void SkDeferredCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000850 SkScalar top, const SkPaint* paint) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000851 SkRect bitmapRect = SkRect::MakeXYWH(left, top,
852 SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
rmistry@google.comd6176b02012-08-23 18:14:13 +0000853 if (fDeferredDrawing &&
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000854 this->isFullFrame(&bitmapRect, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000855 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000856 this->getDeferredDevice()->skipPendingCommands();
junov@google.com4370aed2012-01-18 16:21:08 +0000857 }
858
junov@chromium.org10f7f972012-07-31 21:01:51 +0000859 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000860 this->drawingCanvas()->drawBitmap(bitmap, left, top, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000861 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000862}
863
reed@google.com71121732012-09-18 15:14:33 +0000864void SkDeferredCanvas::drawBitmapRectToRect(const SkBitmap& bitmap,
865 const SkRect* src,
866 const SkRect& dst,
867 const SkPaint* paint) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000868 if (fDeferredDrawing &&
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000869 this->isFullFrame(&dst, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000870 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000871 this->getDeferredDevice()->skipPendingCommands();
junov@google.com4370aed2012-01-18 16:21:08 +0000872 }
873
junov@chromium.org10f7f972012-07-31 21:01:51 +0000874 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
reed@google.com71121732012-09-18 15:14:33 +0000875 this->drawingCanvas()->drawBitmapRectToRect(bitmap, src, dst, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000876 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000877}
878
879
880void SkDeferredCanvas::drawBitmapMatrix(const SkBitmap& bitmap,
881 const SkMatrix& m,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000882 const SkPaint* paint) {
junov@google.com4370aed2012-01-18 16:21:08 +0000883 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
884 // covers canvas entirely and transformed bitmap covers canvas entirely
junov@chromium.org10f7f972012-07-31 21:01:51 +0000885 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000886 this->drawingCanvas()->drawBitmapMatrix(bitmap, m, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000887 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000888}
889
890void SkDeferredCanvas::drawBitmapNine(const SkBitmap& bitmap,
891 const SkIRect& center, const SkRect& dst,
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 dst 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()->drawBitmapNine(bitmap, center, dst, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000897 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000898}
899
900void SkDeferredCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000901 const SkPaint* paint) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000902 SkRect bitmapRect = SkRect::MakeXYWH(
903 SkIntToScalar(left),
rmistry@google.comd6176b02012-08-23 18:14:13 +0000904 SkIntToScalar(top),
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000905 SkIntToScalar(bitmap.width()),
906 SkIntToScalar(bitmap.height()));
rmistry@google.comd6176b02012-08-23 18:14:13 +0000907 if (fDeferredDrawing &&
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000908 this->isFullFrame(&bitmapRect, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000909 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000910 this->getDeferredDevice()->skipPendingCommands();
junov@google.com4370aed2012-01-18 16:21:08 +0000911 }
912
junov@chromium.org10f7f972012-07-31 21:01:51 +0000913 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000914 this->drawingCanvas()->drawSprite(bitmap, left, top, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000915 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000916}
917
918void SkDeferredCanvas::drawText(const void* text, size_t byteLength,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000919 SkScalar x, SkScalar y, const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000920 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000921 this->drawingCanvas()->drawText(text, byteLength, x, y, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000922 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000923}
924
925void SkDeferredCanvas::drawPosText(const void* text, size_t byteLength,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000926 const SkPoint pos[], const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000927 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000928 this->drawingCanvas()->drawPosText(text, byteLength, pos, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000929 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000930}
931
932void SkDeferredCanvas::drawPosTextH(const void* text, size_t byteLength,
933 const SkScalar xpos[], SkScalar constY,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000934 const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000935 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000936 this->drawingCanvas()->drawPosTextH(text, byteLength, xpos, constY, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000937 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000938}
939
940void SkDeferredCanvas::drawTextOnPath(const void* text, size_t byteLength,
941 const SkPath& path,
942 const SkMatrix* matrix,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000943 const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000944 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000945 this->drawingCanvas()->drawTextOnPath(text, byteLength, path, matrix, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000946 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000947}
948
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000949void SkDeferredCanvas::drawPicture(SkPicture& picture) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000950 this->drawingCanvas()->drawPicture(picture);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000951 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000952}
953
954void SkDeferredCanvas::drawVertices(VertexMode vmode, int vertexCount,
955 const SkPoint vertices[],
956 const SkPoint texs[],
957 const SkColor colors[], SkXfermode* xmode,
958 const uint16_t indices[], int indexCount,
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()->drawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
962 indices, indexCount, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000963 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000964}
965
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000966SkBounder* SkDeferredCanvas::setBounder(SkBounder* bounder) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000967 this->drawingCanvas()->setBounder(bounder);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000968 this->INHERITED::setBounder(bounder);
969 this->recordedDrawCommand();
970 return bounder;
junov@google.com4370aed2012-01-18 16:21:08 +0000971}
972
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000973SkDrawFilter* SkDeferredCanvas::setDrawFilter(SkDrawFilter* filter) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000974 this->drawingCanvas()->setDrawFilter(filter);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000975 this->INHERITED::setDrawFilter(filter);
976 this->recordedDrawCommand();
rmistry@google.comd6176b02012-08-23 18:14:13 +0000977 return filter;
junov@google.com4370aed2012-01-18 16:21:08 +0000978}
979
980SkCanvas* SkDeferredCanvas::canvasForDrawIter() {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000981 return this->drawingCanvas();
junov@google.com4370aed2012-01-18 16:21:08 +0000982}