blob: a3306c52a3f3f9fc33aa254d402e6c25f3452d57 [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
junov@chromium.orgbfeddae2012-07-23 13:35:14 +000019enum {
20 // Deferred canvas will auto-flush when recording reaches this limit
21 kDefaultMaxRecordingStorageBytes = 64*1024*1024,
22};
23
junov@google.com4370aed2012-01-18 16:21:08 +000024namespace {
junov@chromium.org10f7f972012-07-31 21:01:51 +000025bool shouldDrawImmediately(const SkBitmap* bitmap, const SkPaint* paint) {
26 if (bitmap && bitmap->getTexture() && !bitmap->isImmutable()) {
27 return true;
28 }
29 if (paint) {
30 SkShader* shader = paint->getShader();
31 // Here we detect the case where the shader is an SkBitmapProcShader
32 // with a gpu texture attached. Checking this without RTTI
33 // requires making the assumption that only gradient shaders
34 // and SkBitmapProcShader implement asABitmap(). The following
35 // code may need to be revised if that assumption is ever broken.
36 if (shader && !shader->asAGradient(NULL)) {
37 SkBitmap bm;
rmistry@google.comd6176b02012-08-23 18:14:13 +000038 if (shader->asABitmap(&bm, NULL, NULL) &&
junov@chromium.org10f7f972012-07-31 21:01:51 +000039 NULL != bm.getTexture()) {
40 return true;
41 }
42 }
43 }
44 return false;
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +000045}
46}
47
48class AutoImmediateDrawIfNeeded {
49public:
rmistry@google.comd6176b02012-08-23 18:14:13 +000050 AutoImmediateDrawIfNeeded(SkDeferredCanvas& canvas, const SkBitmap* bitmap,
junov@chromium.org10f7f972012-07-31 21:01:51 +000051 const SkPaint* paint) {
52 this->init(canvas, bitmap, paint);
53 }
54
55 AutoImmediateDrawIfNeeded(SkDeferredCanvas& canvas, const SkPaint* paint) {
56 this->init(canvas, NULL, paint);
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +000057 }
58
59 ~AutoImmediateDrawIfNeeded() {
60 if (fCanvas) {
61 fCanvas->setDeferredDrawing(true);
62 }
63 }
64private:
junov@chromium.org10f7f972012-07-31 21:01:51 +000065 void init(SkDeferredCanvas& canvas, const SkBitmap* bitmap, const SkPaint* paint)
66 {
67 if (canvas.isDeferredDrawing() && shouldDrawImmediately(bitmap, paint)) {
68 canvas.setDeferredDrawing(false);
69 fCanvas = &canvas;
70 } else {
71 fCanvas = NULL;
72 }
73 }
74
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +000075 SkDeferredCanvas* fCanvas;
76};
77
78namespace {
junov@google.com4370aed2012-01-18 16:21:08 +000079
rmistry@google.comd6176b02012-08-23 18:14:13 +000080bool isPaintOpaque(const SkPaint* paint,
junov@chromium.orgc16ca922012-02-24 22:06:27 +000081 const SkBitmap* bmpReplacesShader = NULL) {
junov@google.com4370aed2012-01-18 16:21:08 +000082 // TODO: SkXfermode should have a virtual isOpaque method, which would
83 // make it possible to test modes that do not have a Coeff representation.
junov@chromium.org87f982c2012-02-23 21:34:34 +000084
85 if (!paint) {
86 return bmpReplacesShader ? bmpReplacesShader->isOpaque() : true;
87 }
88
junov@google.com4370aed2012-01-18 16:21:08 +000089 SkXfermode::Coeff srcCoeff, dstCoeff;
junov@chromium.org87f982c2012-02-23 21:34:34 +000090 if (SkXfermode::AsCoeff(paint->getXfermode(), &srcCoeff, &dstCoeff)){
junov@google.com4370aed2012-01-18 16:21:08 +000091 switch (dstCoeff) {
92 case SkXfermode::kZero_Coeff:
93 return true;
94 case SkXfermode::kISA_Coeff:
junov@chromium.org87f982c2012-02-23 21:34:34 +000095 if (paint->getAlpha() != 255) {
junov@google.com4370aed2012-01-18 16:21:08 +000096 break;
97 }
98 if (bmpReplacesShader) {
99 if (!bmpReplacesShader->isOpaque()) {
100 break;
101 }
junov@chromium.org87f982c2012-02-23 21:34:34 +0000102 } else if (paint->getShader() && !paint->getShader()->isOpaque()) {
junov@google.com4370aed2012-01-18 16:21:08 +0000103 break;
104 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000105 if (paint->getColorFilter() &&
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000106 ((paint->getColorFilter()->getFlags() &
junov@google.com4370aed2012-01-18 16:21:08 +0000107 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
108 break;
109 }
110 return true;
111 case SkXfermode::kSA_Coeff:
junov@chromium.org87f982c2012-02-23 21:34:34 +0000112 if (paint->getAlpha() != 0) {
junov@google.com4370aed2012-01-18 16:21:08 +0000113 break;
114 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000115 if (paint->getColorFilter() &&
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000116 ((paint->getColorFilter()->getFlags() &
junov@google.com4370aed2012-01-18 16:21:08 +0000117 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
118 break;
119 }
120 return true;
121 case SkXfermode::kSC_Coeff:
junov@chromium.org87f982c2012-02-23 21:34:34 +0000122 if (paint->getColor() != 0) { // all components must be 0
junov@google.com4370aed2012-01-18 16:21:08 +0000123 break;
124 }
junov@chromium.org87f982c2012-02-23 21:34:34 +0000125 if (bmpReplacesShader || paint->getShader()) {
junov@google.com4370aed2012-01-18 16:21:08 +0000126 break;
127 }
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000128 if (paint->getColorFilter() && (
129 (paint->getColorFilter()->getFlags() &
junov@google.com4370aed2012-01-18 16:21:08 +0000130 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
131 break;
132 }
133 return true;
134 default:
135 break;
136 }
137 }
138 return false;
139}
140
141} // unnamed namespace
142
junov@chromium.org88e29142012-08-07 16:48:22 +0000143//-----------------------------------------------------------------------------
144// DeferredPipeController
145//-----------------------------------------------------------------------------
146
147class DeferredPipeController : public SkGPipeController {
148public:
149 DeferredPipeController();
150 void setPlaybackCanvas(SkCanvas*);
151 virtual ~DeferredPipeController();
152 virtual void* requestBlock(size_t minRequest, size_t* actual) SK_OVERRIDE;
153 virtual void notifyWritten(size_t bytes) SK_OVERRIDE;
junov@chromium.orgfb103892012-09-20 19:35:43 +0000154 void playback(bool silent);
junov@chromium.org88e29142012-08-07 16:48:22 +0000155 void reset();
156 bool hasRecorded() const { return fAllocator.blockCount() != 0; }
157 size_t storageAllocatedForRecording() const { return fAllocator.totalCapacity(); }
158private:
159 enum {
160 kMinBlockSize = 4096
161 };
162 struct PipeBlock {
163 PipeBlock(void* block, size_t size) { fBlock = block, fSize = size; }
164 void* fBlock;
165 size_t fSize;
166 };
167 void* fBlock;
168 size_t fBytesWritten;
169 SkChunkAlloc fAllocator;
170 SkTDArray<PipeBlock> fBlockList;
171 SkGPipeReader fReader;
172};
173
174DeferredPipeController::DeferredPipeController() :
175 fAllocator(kMinBlockSize) {
176 fBlock = NULL;
177 fBytesWritten = 0;
178}
179
180DeferredPipeController::~DeferredPipeController() {
181 fAllocator.reset();
182}
183
184void DeferredPipeController::setPlaybackCanvas(SkCanvas* canvas) {
185 fReader.setCanvas(canvas);
186}
187
188void* DeferredPipeController::requestBlock(size_t minRequest, size_t *actual) {
189 if (fBlock) {
190 // Save the previous block for later
191 PipeBlock previousBloc(fBlock, fBytesWritten);
192 fBlockList.push(previousBloc);
193 }
194 int32_t blockSize = SkMax32(minRequest, kMinBlockSize);
195 fBlock = fAllocator.allocThrow(blockSize);
196 fBytesWritten = 0;
197 *actual = blockSize;
198 return fBlock;
199}
200
201void DeferredPipeController::notifyWritten(size_t bytes) {
202 fBytesWritten += bytes;
203}
204
junov@chromium.orgfb103892012-09-20 19:35:43 +0000205void DeferredPipeController::playback(bool silent) {
206 uint32_t flags = silent ? SkGPipeReader::kSilent_PlaybackFlag : 0;
junov@chromium.org88e29142012-08-07 16:48:22 +0000207 for (int currentBlock = 0; currentBlock < fBlockList.count(); currentBlock++ ) {
junov@chromium.orgfb103892012-09-20 19:35:43 +0000208 fReader.playback(fBlockList[currentBlock].fBlock, fBlockList[currentBlock].fSize,
209 flags);
junov@chromium.org88e29142012-08-07 16:48:22 +0000210 }
211 fBlockList.reset();
212
213 if (fBlock) {
junov@chromium.orgfb103892012-09-20 19:35:43 +0000214 fReader.playback(fBlock, fBytesWritten, flags);
junov@chromium.org88e29142012-08-07 16:48:22 +0000215 fBlock = NULL;
216 }
217
218 // Release all allocated blocks
219 fAllocator.reset();
220}
221
222void DeferredPipeController::reset() {
223 fBlockList.reset();
224 fBlock = NULL;
225 fAllocator.reset();
226}
227
228//-----------------------------------------------------------------------------
229// DeferredDevice
230//-----------------------------------------------------------------------------
231
232class DeferredDevice : public SkDevice {
233public:
234 DeferredDevice(SkDevice* immediateDevice,
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000235 SkDeferredCanvas::NotificationClient* notificationClient = NULL);
junov@chromium.org88e29142012-08-07 16:48:22 +0000236 ~DeferredDevice();
237
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000238 void setNotificationClient(SkDeferredCanvas::NotificationClient* notificationClient);
junov@chromium.org88e29142012-08-07 16:48:22 +0000239 SkCanvas* recordingCanvas();
240 SkCanvas* immediateCanvas() const {return fImmediateCanvas;}
241 SkDevice* immediateDevice() const {return fImmediateDevice;}
242 bool isFreshFrame();
243 size_t storageAllocatedForRecording() const;
244 size_t freeMemoryIfPossible(size_t bytesToFree);
junov@chromium.orgfb103892012-09-20 19:35:43 +0000245 void flushPendingCommands(bool silent);
junov@chromium.org0a67f962012-09-19 22:48:34 +0000246 void skipPendingCommands();
junov@chromium.org88e29142012-08-07 16:48:22 +0000247 void setMaxRecordingStorage(size_t);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000248 void recordedDrawCommand();
junov@chromium.org88e29142012-08-07 16:48:22 +0000249
250 virtual uint32_t getDeviceCapabilities() SK_OVERRIDE;
251 virtual int width() const SK_OVERRIDE;
252 virtual int height() const SK_OVERRIDE;
253 virtual SkGpuRenderTarget* accessRenderTarget() SK_OVERRIDE;
254
255 virtual SkDevice* onCreateCompatibleDevice(SkBitmap::Config config,
256 int width, int height,
257 bool isOpaque,
258 Usage usage) SK_OVERRIDE;
259
260 virtual void writePixels(const SkBitmap& bitmap, int x, int y,
261 SkCanvas::Config8888 config8888) SK_OVERRIDE;
262
263protected:
264 virtual const SkBitmap& onAccessBitmap(SkBitmap*) SK_OVERRIDE;
265 virtual bool onReadPixels(const SkBitmap& bitmap,
266 int x, int y,
267 SkCanvas::Config8888 config8888) SK_OVERRIDE;
268
269 // The following methods are no-ops on a deferred device
270 virtual bool filterTextFlags(const SkPaint& paint, TextFlags*)
271 SK_OVERRIDE
272 {return false;}
273 virtual void setMatrixClip(const SkMatrix&, const SkRegion&,
274 const SkClipStack&) SK_OVERRIDE
275 {}
276
277 // None of the following drawing methods should ever get called on the
278 // deferred device
279 virtual void clear(SkColor color)
280 {SkASSERT(0);}
281 virtual void drawPaint(const SkDraw&, const SkPaint& paint)
282 {SkASSERT(0);}
283 virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode,
284 size_t count, const SkPoint[],
285 const SkPaint& paint)
286 {SkASSERT(0);}
287 virtual void drawRect(const SkDraw&, const SkRect& r,
288 const SkPaint& paint)
289 {SkASSERT(0);}
290 virtual void drawPath(const SkDraw&, const SkPath& path,
291 const SkPaint& paint,
292 const SkMatrix* prePathMatrix = NULL,
293 bool pathIsMutable = false)
294 {SkASSERT(0);}
295 virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap,
296 const SkIRect* srcRectOrNull,
297 const SkMatrix& matrix, const SkPaint& paint)
298 {SkASSERT(0);}
299 virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap,
300 int x, int y, const SkPaint& paint)
301 {SkASSERT(0);}
302 virtual void drawText(const SkDraw&, const void* text, size_t len,
303 SkScalar x, SkScalar y, const SkPaint& paint)
304 {SkASSERT(0);}
305 virtual void drawPosText(const SkDraw&, const void* text, size_t len,
306 const SkScalar pos[], SkScalar constY,
307 int scalarsPerPos, const SkPaint& paint)
308 {SkASSERT(0);}
309 virtual void drawTextOnPath(const SkDraw&, const void* text,
310 size_t len, const SkPath& path,
311 const SkMatrix* matrix,
312 const SkPaint& paint)
313 {SkASSERT(0);}
314 virtual void drawPosTextOnPath(const SkDraw& draw, const void* text,
315 size_t len, const SkPoint pos[],
316 const SkPaint& paint,
317 const SkPath& path,
318 const SkMatrix* matrix)
319 {SkASSERT(0);}
320 virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode,
321 int vertexCount, const SkPoint verts[],
322 const SkPoint texs[], const SkColor colors[],
323 SkXfermode* xmode, const uint16_t indices[],
324 int indexCount, const SkPaint& paint)
325 {SkASSERT(0);}
326 virtual void drawDevice(const SkDraw&, SkDevice*, int x, int y,
327 const SkPaint&)
328 {SkASSERT(0);}
329private:
330 virtual void flush();
331
332 void endRecording();
333 void beginRecording();
334
335 DeferredPipeController fPipeController;
336 SkGPipeWriter fPipeWriter;
337 SkDevice* fImmediateDevice;
338 SkCanvas* fImmediateCanvas;
339 SkCanvas* fRecordingCanvas;
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000340 SkDeferredCanvas::NotificationClient* fNotificationClient;
junov@chromium.org88e29142012-08-07 16:48:22 +0000341 bool fFreshFrame;
342 size_t fMaxRecordingStorageBytes;
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000343 size_t fPreviousStorageAllocated;
junov@chromium.org88e29142012-08-07 16:48:22 +0000344};
345
346DeferredDevice::DeferredDevice(
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000347 SkDevice* immediateDevice, SkDeferredCanvas::NotificationClient* notificationClient) :
junov@chromium.org88e29142012-08-07 16:48:22 +0000348 SkDevice(SkBitmap::kNo_Config, immediateDevice->width(),
349 immediateDevice->height(), immediateDevice->isOpaque())
junov@chromium.orga8db8fe2012-08-15 19:49:22 +0000350 , fRecordingCanvas(NULL)
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000351 , fFreshFrame(true)
352 , fPreviousStorageAllocated(0){
junov@chromium.org88e29142012-08-07 16:48:22 +0000353
354 fMaxRecordingStorageBytes = kDefaultMaxRecordingStorageBytes;
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000355 fNotificationClient = notificationClient;
junov@chromium.org88e29142012-08-07 16:48:22 +0000356 fImmediateDevice = immediateDevice; // ref counted via fImmediateCanvas
357 fImmediateCanvas = SkNEW_ARGS(SkCanvas, (fImmediateDevice));
358 fPipeController.setPlaybackCanvas(fImmediateCanvas);
359 this->beginRecording();
360}
361
362DeferredDevice::~DeferredDevice() {
junov@chromium.orgfb103892012-09-20 19:35:43 +0000363 this->flushPendingCommands(true);
junov@chromium.org88e29142012-08-07 16:48:22 +0000364 SkSafeUnref(fImmediateCanvas);
junov@chromium.org88e29142012-08-07 16:48:22 +0000365}
366
367void DeferredDevice::setMaxRecordingStorage(size_t maxStorage) {
368 fMaxRecordingStorageBytes = maxStorage;
369 this->recordingCanvas(); // Accessing the recording canvas applies the new limit.
370}
371
372void DeferredDevice::endRecording() {
373 fPipeWriter.endRecording();
374 fPipeController.reset();
375 fRecordingCanvas = NULL;
376}
377
378void DeferredDevice::beginRecording() {
junov@chromium.orga8db8fe2012-08-15 19:49:22 +0000379 SkASSERT(NULL == fRecordingCanvas);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000380 fRecordingCanvas = fPipeWriter.startRecording(&fPipeController, 0,
junov@chromium.orga8db8fe2012-08-15 19:49:22 +0000381 fImmediateDevice->width(), fImmediateDevice->height());
junov@chromium.org88e29142012-08-07 16:48:22 +0000382}
rmistry@google.comd6176b02012-08-23 18:14:13 +0000383
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000384void DeferredDevice::setNotificationClient(
385 SkDeferredCanvas::NotificationClient* notificationClient) {
junov@chromium.org52805482012-08-20 14:25:04 +0000386 fNotificationClient = notificationClient;
junov@chromium.org88e29142012-08-07 16:48:22 +0000387}
388
junov@chromium.org0a67f962012-09-19 22:48:34 +0000389void DeferredDevice::skipPendingCommands() {
junov@chromium.org88e29142012-08-07 16:48:22 +0000390 if (!fRecordingCanvas->isDrawingToLayer()) {
391 fFreshFrame = true;
392
393 // TODO: find a way to transfer the state stack and layers
394 // to the new recording canvas. For now, purging only works
junov@chromium.orga8db8fe2012-08-15 19:49:22 +0000395 // with an empty stack. A save count of 1 means an empty stack.
396 SkASSERT(fRecordingCanvas->getSaveCount() >= 1);
397 if (fRecordingCanvas->getSaveCount() == 1) {
junov@chromium.org88e29142012-08-07 16:48:22 +0000398
399 // Save state that is trashed by the purge
400 SkDrawFilter* drawFilter = fRecordingCanvas->getDrawFilter();
401 SkSafeRef(drawFilter); // So that it survives the purge
402 SkMatrix matrix = fRecordingCanvas->getTotalMatrix();
403 SkRegion clipRegion = fRecordingCanvas->getTotalClip();
404
405 // beginRecording creates a new recording canvas and discards the
406 // old one, hence purging deferred draw ops.
407 this->endRecording();
408 this->beginRecording();
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000409 fPreviousStorageAllocated = storageAllocatedForRecording();
junov@chromium.org88e29142012-08-07 16:48:22 +0000410
411 // Restore pre-purge state
412 if (!clipRegion.isEmpty()) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000413 fRecordingCanvas->clipRegion(clipRegion,
junov@chromium.org88e29142012-08-07 16:48:22 +0000414 SkRegion::kReplace_Op);
415 }
416 if (!matrix.isIdentity()) {
417 fRecordingCanvas->setMatrix(matrix);
418 }
419 if (drawFilter) {
420 fRecordingCanvas->setDrawFilter(drawFilter)->unref();
421 }
422 }
423 }
424}
425
426bool DeferredDevice::isFreshFrame() {
427 bool ret = fFreshFrame;
428 fFreshFrame = false;
429 return ret;
430}
431
junov@chromium.orgfb103892012-09-20 19:35:43 +0000432void DeferredDevice::flushPendingCommands(bool silent) {
junov@chromium.org88e29142012-08-07 16:48:22 +0000433 if (!fPipeController.hasRecorded()) {
434 return;
435 }
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000436 if (fNotificationClient) {
437 fNotificationClient->prepareForDraw();
junov@chromium.org88e29142012-08-07 16:48:22 +0000438 }
junov@chromium.org88e29142012-08-07 16:48:22 +0000439 fPipeWriter.flushRecording(true);
junov@chromium.orgfb103892012-09-20 19:35:43 +0000440 fPipeController.playback(silent);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000441 if (fNotificationClient) {
442 fNotificationClient->flushedDrawCommands();
443 }
444 fPreviousStorageAllocated = storageAllocatedForRecording();
junov@chromium.org88e29142012-08-07 16:48:22 +0000445}
446
447void DeferredDevice::flush() {
junov@chromium.orgfb103892012-09-20 19:35:43 +0000448 this->flushPendingCommands(false);
junov@chromium.org88e29142012-08-07 16:48:22 +0000449 fImmediateCanvas->flush();
450}
451
452size_t DeferredDevice::freeMemoryIfPossible(size_t bytesToFree) {
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000453 size_t val = fPipeWriter.freeMemoryIfPossible(bytesToFree);
454 fPreviousStorageAllocated = storageAllocatedForRecording();
455 return val;
junov@chromium.org88e29142012-08-07 16:48:22 +0000456}
457
458size_t DeferredDevice::storageAllocatedForRecording() const {
459 return (fPipeController.storageAllocatedForRecording()
460 + fPipeWriter.storageAllocatedForRecording());
461}
462
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000463void DeferredDevice::recordedDrawCommand() {
junov@chromium.org88e29142012-08-07 16:48:22 +0000464 size_t storageAllocated = this->storageAllocatedForRecording();
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000465
junov@chromium.org88e29142012-08-07 16:48:22 +0000466 if (storageAllocated > fMaxRecordingStorageBytes) {
467 // First, attempt to reduce cache without flushing
468 size_t tryFree = storageAllocated - fMaxRecordingStorageBytes;
469 if (this->freeMemoryIfPossible(tryFree) < tryFree) {
470 // Flush is necessary to free more space.
junov@chromium.orgfb103892012-09-20 19:35:43 +0000471 this->flushPendingCommands(false);
junov@chromium.org88e29142012-08-07 16:48:22 +0000472 // Free as much as possible to avoid oscillating around fMaxRecordingStorageBytes
473 // which could cause a high flushing frequency.
bsalomon@google.com100abf42012-09-05 17:40:04 +0000474 this->freeMemoryIfPossible(~0U);
junov@chromium.org88e29142012-08-07 16:48:22 +0000475 }
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000476 storageAllocated = this->storageAllocatedForRecording();
junov@chromium.org88e29142012-08-07 16:48:22 +0000477 }
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000478
rmistry@google.comd6176b02012-08-23 18:14:13 +0000479 if (fNotificationClient &&
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000480 storageAllocated != fPreviousStorageAllocated) {
481 fPreviousStorageAllocated = storageAllocated;
482 fNotificationClient->storageAllocatedForRecordingChanged(storageAllocated);
483 }
484}
485
486SkCanvas* DeferredDevice::recordingCanvas() {
junov@chromium.org88e29142012-08-07 16:48:22 +0000487 return fRecordingCanvas;
488}
489
rmistry@google.comd6176b02012-08-23 18:14:13 +0000490uint32_t DeferredDevice::getDeviceCapabilities() {
junov@chromium.org88e29142012-08-07 16:48:22 +0000491 return fImmediateDevice->getDeviceCapabilities();
492}
493
rmistry@google.comd6176b02012-08-23 18:14:13 +0000494int DeferredDevice::width() const {
junov@chromium.org88e29142012-08-07 16:48:22 +0000495 return fImmediateDevice->width();
496}
497
498int DeferredDevice::height() const {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000499 return fImmediateDevice->height();
junov@chromium.org88e29142012-08-07 16:48:22 +0000500}
501
502SkGpuRenderTarget* DeferredDevice::accessRenderTarget() {
junov@chromium.orgfb103892012-09-20 19:35:43 +0000503 this->flushPendingCommands(false);
junov@chromium.org88e29142012-08-07 16:48:22 +0000504 return fImmediateDevice->accessRenderTarget();
505}
506
507void DeferredDevice::writePixels(const SkBitmap& bitmap,
508 int x, int y, SkCanvas::Config8888 config8888) {
509
510 if (x <= 0 && y <= 0 && (x + bitmap.width()) >= width() &&
511 (y + bitmap.height()) >= height()) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000512 this->skipPendingCommands();
junov@chromium.org88e29142012-08-07 16:48:22 +0000513 }
514
515 if (SkBitmap::kARGB_8888_Config == bitmap.config() &&
516 SkCanvas::kNative_Premul_Config8888 != config8888 &&
517 kPMColorAlias != config8888) {
518 //Special case config: no deferral
junov@chromium.orgfb103892012-09-20 19:35:43 +0000519 this->flushPendingCommands(false);
junov@chromium.org88e29142012-08-07 16:48:22 +0000520 fImmediateDevice->writePixels(bitmap, x, y, config8888);
521 return;
522 }
523
524 SkPaint paint;
525 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
526 if (shouldDrawImmediately(&bitmap, NULL)) {
junov@chromium.orgfb103892012-09-20 19:35:43 +0000527 this->flushPendingCommands(false);
junov@chromium.org88e29142012-08-07 16:48:22 +0000528 fImmediateCanvas->drawSprite(bitmap, x, y, &paint);
529 } else {
530 this->recordingCanvas()->drawSprite(bitmap, x, y, &paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000531 this->recordedDrawCommand();
532
junov@chromium.org88e29142012-08-07 16:48:22 +0000533 }
534}
535
536const SkBitmap& DeferredDevice::onAccessBitmap(SkBitmap*) {
junov@chromium.orgfb103892012-09-20 19:35:43 +0000537 this->flushPendingCommands(false);
junov@chromium.org88e29142012-08-07 16:48:22 +0000538 return fImmediateDevice->accessBitmap(false);
539}
540
541SkDevice* DeferredDevice::onCreateCompatibleDevice(
542 SkBitmap::Config config, int width, int height, bool isOpaque,
543 Usage usage) {
544
545 // Save layer usage not supported, and not required by SkDeferredCanvas.
546 SkASSERT(usage != kSaveLayer_Usage);
547 // Create a compatible non-deferred device.
548 SkAutoTUnref<SkDevice> compatibleDevice
549 (fImmediateDevice->createCompatibleDevice(config, width, height,
550 isOpaque));
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000551 return SkNEW_ARGS(DeferredDevice, (compatibleDevice, fNotificationClient));
junov@chromium.org88e29142012-08-07 16:48:22 +0000552}
553
554bool DeferredDevice::onReadPixels(
555 const SkBitmap& bitmap, int x, int y, SkCanvas::Config8888 config8888) {
junov@chromium.orgfb103892012-09-20 19:35:43 +0000556 this->flushPendingCommands(false);
junov@chromium.org88e29142012-08-07 16:48:22 +0000557 return fImmediateCanvas->readPixels(const_cast<SkBitmap*>(&bitmap),
558 x, y, config8888);
559}
560
561
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000562SkDeferredCanvas::SkDeferredCanvas() {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000563 this->init();
junov@google.com4370aed2012-01-18 16:21:08 +0000564}
565
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000566SkDeferredCanvas::SkDeferredCanvas(SkDevice* device) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000567 this->init();
568 this->setDevice(device);
junov@google.com4370aed2012-01-18 16:21:08 +0000569}
570
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000571void SkDeferredCanvas::init() {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000572 fDeferredDrawing = true; // On by default
junov@google.com4370aed2012-01-18 16:21:08 +0000573}
574
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000575void SkDeferredCanvas::setMaxRecordingStorage(size_t maxStorage) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000576 this->validate();
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000577 this->getDeferredDevice()->setMaxRecordingStorage(maxStorage);
578}
579
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000580size_t SkDeferredCanvas::storageAllocatedForRecording() const {
581 return this->getDeferredDevice()->storageAllocatedForRecording();
582}
583
584size_t SkDeferredCanvas::freeMemoryIfPossible(size_t bytesToFree) {
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000585 return this->getDeferredDevice()->freeMemoryIfPossible(bytesToFree);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000586}
587
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000588void SkDeferredCanvas::recordedDrawCommand() {
589 if (fDeferredDrawing) {
590 this->getDeferredDevice()->recordedDrawCommand();
591 }
592}
593
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000594void SkDeferredCanvas::validate() const {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000595 SkASSERT(this->getDevice());
junov@google.com4370aed2012-01-18 16:21:08 +0000596}
597
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000598SkCanvas* SkDeferredCanvas::drawingCanvas() const {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000599 this->validate();
600 return fDeferredDrawing ? this->getDeferredDevice()->recordingCanvas() :
601 this->getDeferredDevice()->immediateCanvas();
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000602}
603
junov@chromium.org88e29142012-08-07 16:48:22 +0000604SkCanvas* SkDeferredCanvas::immediateCanvas() const {
605 this->validate();
606 return this->getDeferredDevice()->immediateCanvas();
607}
608
609DeferredDevice* SkDeferredCanvas::getDeferredDevice() const {
610 return static_cast<DeferredDevice*>(this->getDevice());
junov@google.com4370aed2012-01-18 16:21:08 +0000611}
612
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000613void SkDeferredCanvas::setDeferredDrawing(bool val) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000614 this->validate(); // Must set device before calling this method
junov@google.com4370aed2012-01-18 16:21:08 +0000615 if (val != fDeferredDrawing) {
616 if (fDeferredDrawing) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000617 // Going live.
junov@chromium.orgfb103892012-09-20 19:35:43 +0000618 this->getDeferredDevice()->flushPendingCommands(false);
junov@google.com4370aed2012-01-18 16:21:08 +0000619 }
620 fDeferredDrawing = val;
621 }
622}
623
junov@chromium.org88e29142012-08-07 16:48:22 +0000624bool SkDeferredCanvas::isDeferredDrawing() const {
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +0000625 return fDeferredDrawing;
626}
627
junov@chromium.org88e29142012-08-07 16:48:22 +0000628bool SkDeferredCanvas::isFreshFrame() const {
629 return this->getDeferredDevice()->isFreshFrame();
630}
631
junov@chromium.orgfb103892012-09-20 19:35:43 +0000632void SkDeferredCanvas::silentFlush() {
633 if (fDeferredDrawing) {
634 this->getDeferredDevice()->flushPendingCommands(true);
635 }
636}
637
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000638SkDeferredCanvas::~SkDeferredCanvas() {
junov@google.com4370aed2012-01-18 16:21:08 +0000639}
640
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000641SkDevice* SkDeferredCanvas::setDevice(SkDevice* device) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000642 this->INHERITED::setDevice(SkNEW_ARGS(DeferredDevice, (device)))->unref();
junov@google.com4370aed2012-01-18 16:21:08 +0000643 return device;
644}
645
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000646SkDeferredCanvas::NotificationClient* SkDeferredCanvas::setNotificationClient(
647 NotificationClient* notificationClient) {
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000648
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000649 DeferredDevice* deferredDevice = this->getDeferredDevice();
junov@google.com4370aed2012-01-18 16:21:08 +0000650 SkASSERT(deferredDevice);
651 if (deferredDevice) {
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000652 deferredDevice->setNotificationClient(notificationClient);
junov@google.com4370aed2012-01-18 16:21:08 +0000653 }
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000654 return notificationClient;
junov@google.com4370aed2012-01-18 16:21:08 +0000655}
656
657bool SkDeferredCanvas::isFullFrame(const SkRect* rect,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000658 const SkPaint* paint) const {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000659 SkCanvas* canvas = this->drawingCanvas();
660 SkISize canvasSize = this->getDeviceSize();
junov@google.com4370aed2012-01-18 16:21:08 +0000661 if (rect) {
662 if (!canvas->getTotalMatrix().rectStaysRect()) {
663 return false; // conservative
664 }
665
666 SkRect transformedRect;
667 canvas->getTotalMatrix().mapRect(&transformedRect, *rect);
668
669 if (paint) {
670 SkPaint::Style paintStyle = paint->getStyle();
rmistry@google.comd6176b02012-08-23 18:14:13 +0000671 if (!(paintStyle == SkPaint::kFill_Style ||
junov@google.com4370aed2012-01-18 16:21:08 +0000672 paintStyle == SkPaint::kStrokeAndFill_Style)) {
673 return false;
674 }
675 if (paint->getMaskFilter() || paint->getLooper()
676 || paint->getPathEffect() || paint->getImageFilter()) {
677 return false; // conservative
678 }
679 }
680
681 // The following test holds with AA enabled, and is conservative
682 // by a 0.5 pixel margin with AA disabled
rmistry@google.comd6176b02012-08-23 18:14:13 +0000683 if (transformedRect.fLeft > SkIntToScalar(0) ||
684 transformedRect.fTop > SkIntToScalar(0) ||
junov@chromium.orgb1e218e2012-02-13 22:27:58 +0000685 transformedRect.fRight < SkIntToScalar(canvasSize.fWidth) ||
686 transformedRect.fBottom < SkIntToScalar(canvasSize.fHeight)) {
junov@google.com4370aed2012-01-18 16:21:08 +0000687 return false;
688 }
689 }
690
691 switch (canvas->getClipType()) {
692 case SkCanvas::kRect_ClipType :
693 {
694 SkIRect bounds;
695 canvas->getClipDeviceBounds(&bounds);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000696 if (bounds.fLeft > 0 || bounds.fTop > 0 ||
697 bounds.fRight < canvasSize.fWidth ||
junov@google.com4370aed2012-01-18 16:21:08 +0000698 bounds.fBottom < canvasSize.fHeight)
699 return false;
700 }
701 break;
702 case SkCanvas::kComplex_ClipType :
703 return false; // conservative
704 case SkCanvas::kEmpty_ClipType:
705 default:
706 break;
707 };
708
709 return true;
710}
711
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000712int SkDeferredCanvas::save(SaveFlags flags) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000713 this->drawingCanvas()->save(flags);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000714 int val = this->INHERITED::save(flags);
715 this->recordedDrawCommand();
716
717 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000718}
719
720int SkDeferredCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000721 SaveFlags flags) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000722 this->drawingCanvas()->saveLayer(bounds, paint, flags);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000723 int count = this->INHERITED::save(flags);
724 this->clipRectBounds(bounds, flags, NULL);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000725 this->recordedDrawCommand();
726
junov@chromium.orga907ac32012-02-24 21:54:07 +0000727 return count;
junov@google.com4370aed2012-01-18 16:21:08 +0000728}
729
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000730void SkDeferredCanvas::restore() {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000731 this->drawingCanvas()->restore();
junov@chromium.orga907ac32012-02-24 21:54:07 +0000732 this->INHERITED::restore();
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000733 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000734}
735
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000736bool SkDeferredCanvas::isDrawingToLayer() const {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000737 return this->drawingCanvas()->isDrawingToLayer();
junov@google.com4370aed2012-01-18 16:21:08 +0000738}
739
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000740bool SkDeferredCanvas::translate(SkScalar dx, SkScalar dy) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000741 this->drawingCanvas()->translate(dx, dy);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000742 bool val = this->INHERITED::translate(dx, dy);
743 this->recordedDrawCommand();
744 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000745}
746
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000747bool SkDeferredCanvas::scale(SkScalar sx, SkScalar sy) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000748 this->drawingCanvas()->scale(sx, sy);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000749 bool val = this->INHERITED::scale(sx, sy);
750 this->recordedDrawCommand();
751 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000752}
753
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000754bool SkDeferredCanvas::rotate(SkScalar degrees) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000755 this->drawingCanvas()->rotate(degrees);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000756 bool val = this->INHERITED::rotate(degrees);
757 this->recordedDrawCommand();
758 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000759}
760
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000761bool SkDeferredCanvas::skew(SkScalar sx, SkScalar sy) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000762 this->drawingCanvas()->skew(sx, sy);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000763 bool val = this->INHERITED::skew(sx, sy);
764 this->recordedDrawCommand();
765 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000766}
767
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000768bool SkDeferredCanvas::concat(const SkMatrix& matrix) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000769 this->drawingCanvas()->concat(matrix);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000770 bool val = this->INHERITED::concat(matrix);
771 this->recordedDrawCommand();
772 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000773}
774
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000775void SkDeferredCanvas::setMatrix(const SkMatrix& matrix) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000776 this->drawingCanvas()->setMatrix(matrix);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000777 this->INHERITED::setMatrix(matrix);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000778 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000779}
780
781bool SkDeferredCanvas::clipRect(const SkRect& rect,
782 SkRegion::Op op,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000783 bool doAntiAlias) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000784 this->drawingCanvas()->clipRect(rect, op, doAntiAlias);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000785 bool val = this->INHERITED::clipRect(rect, op, doAntiAlias);
786 this->recordedDrawCommand();
787 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000788}
789
790bool SkDeferredCanvas::clipPath(const SkPath& path,
791 SkRegion::Op op,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000792 bool doAntiAlias) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000793 this->drawingCanvas()->clipPath(path, op, doAntiAlias);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000794 bool val = this->INHERITED::clipPath(path, op, doAntiAlias);
795 this->recordedDrawCommand();
796 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000797}
798
799bool SkDeferredCanvas::clipRegion(const SkRegion& deviceRgn,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000800 SkRegion::Op op) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000801 this->drawingCanvas()->clipRegion(deviceRgn, op);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000802 bool val = this->INHERITED::clipRegion(deviceRgn, op);
803 this->recordedDrawCommand();
804 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000805}
806
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000807void SkDeferredCanvas::clear(SkColor color) {
junov@google.com4370aed2012-01-18 16:21:08 +0000808 // purge pending commands
809 if (fDeferredDrawing) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000810 this->getDeferredDevice()->skipPendingCommands();
junov@google.com4370aed2012-01-18 16:21:08 +0000811 }
812
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000813 this->drawingCanvas()->clear(color);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000814 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000815}
816
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000817void SkDeferredCanvas::drawPaint(const SkPaint& paint) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000818 if (fDeferredDrawing && this->isFullFrame(NULL, &paint) &&
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000819 isPaintOpaque(&paint)) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000820 this->getDeferredDevice()->skipPendingCommands();
junov@google.com4370aed2012-01-18 16:21:08 +0000821 }
junov@chromium.org10f7f972012-07-31 21:01:51 +0000822 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000823 this->drawingCanvas()->drawPaint(paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000824 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000825}
826
827void SkDeferredCanvas::drawPoints(PointMode mode, size_t count,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000828 const SkPoint pts[], const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000829 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000830 this->drawingCanvas()->drawPoints(mode, count, pts, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000831 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000832}
833
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000834void SkDeferredCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000835 if (fDeferredDrawing && this->isFullFrame(&rect, &paint) &&
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000836 isPaintOpaque(&paint)) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000837 this->getDeferredDevice()->skipPendingCommands();
junov@google.com4370aed2012-01-18 16:21:08 +0000838 }
839
junov@chromium.org10f7f972012-07-31 21:01:51 +0000840 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000841 this->drawingCanvas()->drawRect(rect, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000842 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000843}
844
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000845void SkDeferredCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000846 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000847 this->drawingCanvas()->drawPath(path, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000848 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000849}
850
851void SkDeferredCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000852 SkScalar top, const SkPaint* paint) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000853 SkRect bitmapRect = SkRect::MakeXYWH(left, top,
854 SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
rmistry@google.comd6176b02012-08-23 18:14:13 +0000855 if (fDeferredDrawing &&
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000856 this->isFullFrame(&bitmapRect, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000857 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000858 this->getDeferredDevice()->skipPendingCommands();
junov@google.com4370aed2012-01-18 16:21:08 +0000859 }
860
junov@chromium.org10f7f972012-07-31 21:01:51 +0000861 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000862 this->drawingCanvas()->drawBitmap(bitmap, left, top, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000863 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000864}
865
reed@google.com71121732012-09-18 15:14:33 +0000866void SkDeferredCanvas::drawBitmapRectToRect(const SkBitmap& bitmap,
867 const SkRect* src,
868 const SkRect& dst,
869 const SkPaint* paint) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000870 if (fDeferredDrawing &&
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000871 this->isFullFrame(&dst, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000872 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000873 this->getDeferredDevice()->skipPendingCommands();
junov@google.com4370aed2012-01-18 16:21:08 +0000874 }
875
junov@chromium.org10f7f972012-07-31 21:01:51 +0000876 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
reed@google.com71121732012-09-18 15:14:33 +0000877 this->drawingCanvas()->drawBitmapRectToRect(bitmap, src, dst, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000878 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000879}
880
881
882void SkDeferredCanvas::drawBitmapMatrix(const SkBitmap& bitmap,
883 const SkMatrix& m,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000884 const SkPaint* paint) {
junov@google.com4370aed2012-01-18 16:21:08 +0000885 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
886 // covers canvas entirely and transformed bitmap covers canvas entirely
junov@chromium.org10f7f972012-07-31 21:01:51 +0000887 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000888 this->drawingCanvas()->drawBitmapMatrix(bitmap, m, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000889 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000890}
891
892void SkDeferredCanvas::drawBitmapNine(const SkBitmap& bitmap,
893 const SkIRect& center, const SkRect& dst,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000894 const SkPaint* paint) {
junov@google.com4370aed2012-01-18 16:21:08 +0000895 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
896 // covers canvas entirely and dst covers canvas entirely
junov@chromium.org10f7f972012-07-31 21:01:51 +0000897 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000898 this->drawingCanvas()->drawBitmapNine(bitmap, center, dst, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000899 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000900}
901
902void SkDeferredCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000903 const SkPaint* paint) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000904 SkRect bitmapRect = SkRect::MakeXYWH(
905 SkIntToScalar(left),
rmistry@google.comd6176b02012-08-23 18:14:13 +0000906 SkIntToScalar(top),
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000907 SkIntToScalar(bitmap.width()),
908 SkIntToScalar(bitmap.height()));
rmistry@google.comd6176b02012-08-23 18:14:13 +0000909 if (fDeferredDrawing &&
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000910 this->isFullFrame(&bitmapRect, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000911 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000912 this->getDeferredDevice()->skipPendingCommands();
junov@google.com4370aed2012-01-18 16:21:08 +0000913 }
914
junov@chromium.org10f7f972012-07-31 21:01:51 +0000915 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000916 this->drawingCanvas()->drawSprite(bitmap, left, top, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000917 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000918}
919
920void SkDeferredCanvas::drawText(const void* text, size_t byteLength,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000921 SkScalar x, SkScalar y, const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000922 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000923 this->drawingCanvas()->drawText(text, byteLength, x, y, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000924 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000925}
926
927void SkDeferredCanvas::drawPosText(const void* text, size_t byteLength,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000928 const SkPoint pos[], const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000929 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000930 this->drawingCanvas()->drawPosText(text, byteLength, pos, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000931 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000932}
933
934void SkDeferredCanvas::drawPosTextH(const void* text, size_t byteLength,
935 const SkScalar xpos[], SkScalar constY,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000936 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()->drawPosTextH(text, byteLength, xpos, constY, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000939 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000940}
941
942void SkDeferredCanvas::drawTextOnPath(const void* text, size_t byteLength,
943 const SkPath& path,
944 const SkMatrix* matrix,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000945 const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000946 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000947 this->drawingCanvas()->drawTextOnPath(text, byteLength, path, matrix, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000948 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000949}
950
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000951void SkDeferredCanvas::drawPicture(SkPicture& picture) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000952 this->drawingCanvas()->drawPicture(picture);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000953 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000954}
955
956void SkDeferredCanvas::drawVertices(VertexMode vmode, int vertexCount,
957 const SkPoint vertices[],
958 const SkPoint texs[],
959 const SkColor colors[], SkXfermode* xmode,
960 const uint16_t indices[], int indexCount,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000961 const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000962 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000963 this->drawingCanvas()->drawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
964 indices, indexCount, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000965 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000966}
967
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000968SkBounder* SkDeferredCanvas::setBounder(SkBounder* bounder) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000969 this->drawingCanvas()->setBounder(bounder);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000970 this->INHERITED::setBounder(bounder);
971 this->recordedDrawCommand();
972 return bounder;
junov@google.com4370aed2012-01-18 16:21:08 +0000973}
974
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000975SkDrawFilter* SkDeferredCanvas::setDrawFilter(SkDrawFilter* filter) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000976 this->drawingCanvas()->setDrawFilter(filter);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000977 this->INHERITED::setDrawFilter(filter);
978 this->recordedDrawCommand();
rmistry@google.comd6176b02012-08-23 18:14:13 +0000979 return filter;
junov@google.com4370aed2012-01-18 16:21:08 +0000980}
981
982SkCanvas* SkDeferredCanvas::canvasForDrawIter() {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000983 return this->drawingCanvas();
junov@google.com4370aed2012-01-18 16:21:08 +0000984}