blob: 6259f949ee86ae25715292b10fe81e6bbbf68954 [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
reed@google.com563a3b42012-06-26 19:24:50 +000019SK_DEFINE_INST_COUNT(SkDeferredCanvas::DeviceContext)
20
junov@chromium.orgbfeddae2012-07-23 13:35:14 +000021enum {
22 // Deferred canvas will auto-flush when recording reaches this limit
23 kDefaultMaxRecordingStorageBytes = 64*1024*1024,
24};
25
junov@google.com4370aed2012-01-18 16:21:08 +000026namespace {
junov@chromium.org10f7f972012-07-31 21:01:51 +000027bool shouldDrawImmediately(const SkBitmap* bitmap, const SkPaint* paint) {
28 if (bitmap && bitmap->getTexture() && !bitmap->isImmutable()) {
29 return true;
30 }
31 if (paint) {
32 SkShader* shader = paint->getShader();
33 // Here we detect the case where the shader is an SkBitmapProcShader
34 // with a gpu texture attached. Checking this without RTTI
35 // requires making the assumption that only gradient shaders
36 // and SkBitmapProcShader implement asABitmap(). The following
37 // code may need to be revised if that assumption is ever broken.
38 if (shader && !shader->asAGradient(NULL)) {
39 SkBitmap bm;
40 if (shader->asABitmap(&bm, NULL, NULL) &&
41 NULL != bm.getTexture()) {
42 return true;
43 }
44 }
45 }
46 return false;
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +000047}
48}
49
50class AutoImmediateDrawIfNeeded {
51public:
junov@chromium.org10f7f972012-07-31 21:01:51 +000052 AutoImmediateDrawIfNeeded(SkDeferredCanvas& canvas, const SkBitmap* bitmap,
53 const SkPaint* paint) {
54 this->init(canvas, bitmap, paint);
55 }
56
57 AutoImmediateDrawIfNeeded(SkDeferredCanvas& canvas, const SkPaint* paint) {
58 this->init(canvas, NULL, paint);
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +000059 }
60
61 ~AutoImmediateDrawIfNeeded() {
62 if (fCanvas) {
63 fCanvas->setDeferredDrawing(true);
64 }
65 }
66private:
junov@chromium.org10f7f972012-07-31 21:01:51 +000067 void init(SkDeferredCanvas& canvas, const SkBitmap* bitmap, const SkPaint* paint)
68 {
69 if (canvas.isDeferredDrawing() && shouldDrawImmediately(bitmap, paint)) {
70 canvas.setDeferredDrawing(false);
71 fCanvas = &canvas;
72 } else {
73 fCanvas = NULL;
74 }
75 }
76
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +000077 SkDeferredCanvas* fCanvas;
78};
79
80namespace {
junov@google.com4370aed2012-01-18 16:21:08 +000081
junov@chromium.orgc16ca922012-02-24 22:06:27 +000082bool isPaintOpaque(const SkPaint* paint,
83 const SkBitmap* bmpReplacesShader = NULL) {
junov@google.com4370aed2012-01-18 16:21:08 +000084 // TODO: SkXfermode should have a virtual isOpaque method, which would
85 // make it possible to test modes that do not have a Coeff representation.
junov@chromium.org87f982c2012-02-23 21:34:34 +000086
87 if (!paint) {
88 return bmpReplacesShader ? bmpReplacesShader->isOpaque() : true;
89 }
90
junov@google.com4370aed2012-01-18 16:21:08 +000091 SkXfermode::Coeff srcCoeff, dstCoeff;
junov@chromium.org87f982c2012-02-23 21:34:34 +000092 if (SkXfermode::AsCoeff(paint->getXfermode(), &srcCoeff, &dstCoeff)){
junov@google.com4370aed2012-01-18 16:21:08 +000093 switch (dstCoeff) {
94 case SkXfermode::kZero_Coeff:
95 return true;
96 case SkXfermode::kISA_Coeff:
junov@chromium.org87f982c2012-02-23 21:34:34 +000097 if (paint->getAlpha() != 255) {
junov@google.com4370aed2012-01-18 16:21:08 +000098 break;
99 }
100 if (bmpReplacesShader) {
101 if (!bmpReplacesShader->isOpaque()) {
102 break;
103 }
junov@chromium.org87f982c2012-02-23 21:34:34 +0000104 } else if (paint->getShader() && !paint->getShader()->isOpaque()) {
junov@google.com4370aed2012-01-18 16:21:08 +0000105 break;
106 }
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000107 if (paint->getColorFilter() &&
108 ((paint->getColorFilter()->getFlags() &
junov@google.com4370aed2012-01-18 16:21:08 +0000109 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
110 break;
111 }
112 return true;
113 case SkXfermode::kSA_Coeff:
junov@chromium.org87f982c2012-02-23 21:34:34 +0000114 if (paint->getAlpha() != 0) {
junov@google.com4370aed2012-01-18 16:21:08 +0000115 break;
116 }
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000117 if (paint->getColorFilter() &&
118 ((paint->getColorFilter()->getFlags() &
junov@google.com4370aed2012-01-18 16:21:08 +0000119 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
120 break;
121 }
122 return true;
123 case SkXfermode::kSC_Coeff:
junov@chromium.org87f982c2012-02-23 21:34:34 +0000124 if (paint->getColor() != 0) { // all components must be 0
junov@google.com4370aed2012-01-18 16:21:08 +0000125 break;
126 }
junov@chromium.org87f982c2012-02-23 21:34:34 +0000127 if (bmpReplacesShader || paint->getShader()) {
junov@google.com4370aed2012-01-18 16:21:08 +0000128 break;
129 }
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000130 if (paint->getColorFilter() && (
131 (paint->getColorFilter()->getFlags() &
junov@google.com4370aed2012-01-18 16:21:08 +0000132 SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
133 break;
134 }
135 return true;
136 default:
137 break;
138 }
139 }
140 return false;
141}
142
143} // unnamed namespace
144
junov@chromium.org88e29142012-08-07 16:48:22 +0000145//-----------------------------------------------------------------------------
146// DeferredPipeController
147//-----------------------------------------------------------------------------
148
149class DeferredPipeController : public SkGPipeController {
150public:
151 DeferredPipeController();
152 void setPlaybackCanvas(SkCanvas*);
153 virtual ~DeferredPipeController();
154 virtual void* requestBlock(size_t minRequest, size_t* actual) SK_OVERRIDE;
155 virtual void notifyWritten(size_t bytes) SK_OVERRIDE;
156 void playback();
157 void reset();
158 bool hasRecorded() const { return fAllocator.blockCount() != 0; }
159 size_t storageAllocatedForRecording() const { return fAllocator.totalCapacity(); }
160private:
161 enum {
162 kMinBlockSize = 4096
163 };
164 struct PipeBlock {
165 PipeBlock(void* block, size_t size) { fBlock = block, fSize = size; }
166 void* fBlock;
167 size_t fSize;
168 };
169 void* fBlock;
170 size_t fBytesWritten;
171 SkChunkAlloc fAllocator;
172 SkTDArray<PipeBlock> fBlockList;
173 SkGPipeReader fReader;
174};
175
176DeferredPipeController::DeferredPipeController() :
177 fAllocator(kMinBlockSize) {
178 fBlock = NULL;
179 fBytesWritten = 0;
180}
181
182DeferredPipeController::~DeferredPipeController() {
183 fAllocator.reset();
184}
185
186void DeferredPipeController::setPlaybackCanvas(SkCanvas* canvas) {
187 fReader.setCanvas(canvas);
188}
189
190void* DeferredPipeController::requestBlock(size_t minRequest, size_t *actual) {
191 if (fBlock) {
192 // Save the previous block for later
193 PipeBlock previousBloc(fBlock, fBytesWritten);
194 fBlockList.push(previousBloc);
195 }
196 int32_t blockSize = SkMax32(minRequest, kMinBlockSize);
197 fBlock = fAllocator.allocThrow(blockSize);
198 fBytesWritten = 0;
199 *actual = blockSize;
200 return fBlock;
201}
202
203void DeferredPipeController::notifyWritten(size_t bytes) {
204 fBytesWritten += bytes;
205}
206
207void DeferredPipeController::playback() {
208
209 for (int currentBlock = 0; currentBlock < fBlockList.count(); currentBlock++ ) {
210 fReader.playback(fBlockList[currentBlock].fBlock, fBlockList[currentBlock].fSize);
211 }
212 fBlockList.reset();
213
214 if (fBlock) {
215 fReader.playback(fBlock, fBytesWritten);
216 fBlock = NULL;
217 }
218
219 // Release all allocated blocks
220 fAllocator.reset();
221}
222
223void DeferredPipeController::reset() {
224 fBlockList.reset();
225 fBlock = NULL;
226 fAllocator.reset();
227}
228
229//-----------------------------------------------------------------------------
230// DeferredDevice
231//-----------------------------------------------------------------------------
232
233class DeferredDevice : public SkDevice {
234public:
235 DeferredDevice(SkDevice* immediateDevice,
236 SkDeferredCanvas::DeviceContext* deviceContext = NULL);
237 ~DeferredDevice();
238
239 void setDeviceContext(SkDeferredCanvas::DeviceContext* deviceContext);
240 SkCanvas* recordingCanvas();
241 SkCanvas* immediateCanvas() const {return fImmediateCanvas;}
242 SkDevice* immediateDevice() const {return fImmediateDevice;}
243 bool isFreshFrame();
244 size_t storageAllocatedForRecording() const;
245 size_t freeMemoryIfPossible(size_t bytesToFree);
246 void flushPending();
247 void contentsCleared();
248 void setMaxRecordingStorage(size_t);
249
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;
340 SkDeferredCanvas::DeviceContext* fDeviceContext;
341 bool fFreshFrame;
342 size_t fMaxRecordingStorageBytes;
343};
344
345DeferredDevice::DeferredDevice(
346 SkDevice* immediateDevice, SkDeferredCanvas::DeviceContext* deviceContext) :
347 SkDevice(SkBitmap::kNo_Config, immediateDevice->width(),
348 immediateDevice->height(), immediateDevice->isOpaque())
349 , fFreshFrame(true) {
350
351 fMaxRecordingStorageBytes = kDefaultMaxRecordingStorageBytes;
352 fDeviceContext = deviceContext;
353 SkSafeRef(fDeviceContext);
354 fImmediateDevice = immediateDevice; // ref counted via fImmediateCanvas
355 fImmediateCanvas = SkNEW_ARGS(SkCanvas, (fImmediateDevice));
356 fPipeController.setPlaybackCanvas(fImmediateCanvas);
357 this->beginRecording();
358}
359
360DeferredDevice::~DeferredDevice() {
361 this->flushPending();
362 SkSafeUnref(fImmediateCanvas);
363 SkSafeUnref(fDeviceContext);
364}
365
366void DeferredDevice::setMaxRecordingStorage(size_t maxStorage) {
367 fMaxRecordingStorageBytes = maxStorage;
368 this->recordingCanvas(); // Accessing the recording canvas applies the new limit.
369}
370
371void DeferredDevice::endRecording() {
372 fPipeWriter.endRecording();
373 fPipeController.reset();
374 fRecordingCanvas = NULL;
375}
376
377void DeferredDevice::beginRecording() {
378 fRecordingCanvas = fPipeWriter.startRecording(&fPipeController, 0);
379}
380
381void DeferredDevice::setDeviceContext(
382 SkDeferredCanvas::DeviceContext* deviceContext) {
383 SkRefCnt_SafeAssign(fDeviceContext, deviceContext);
384}
385
386void DeferredDevice::contentsCleared() {
387 if (!fRecordingCanvas->isDrawingToLayer()) {
388 fFreshFrame = true;
389
390 // TODO: find a way to transfer the state stack and layers
391 // to the new recording canvas. For now, purging only works
392 // with an empty stack.
393 if (fRecordingCanvas->getSaveCount() == 0) {
394
395 // Save state that is trashed by the purge
396 SkDrawFilter* drawFilter = fRecordingCanvas->getDrawFilter();
397 SkSafeRef(drawFilter); // So that it survives the purge
398 SkMatrix matrix = fRecordingCanvas->getTotalMatrix();
399 SkRegion clipRegion = fRecordingCanvas->getTotalClip();
400
401 // beginRecording creates a new recording canvas and discards the
402 // old one, hence purging deferred draw ops.
403 this->endRecording();
404 this->beginRecording();
405
406 // Restore pre-purge state
407 if (!clipRegion.isEmpty()) {
408 fRecordingCanvas->clipRegion(clipRegion,
409 SkRegion::kReplace_Op);
410 }
411 if (!matrix.isIdentity()) {
412 fRecordingCanvas->setMatrix(matrix);
413 }
414 if (drawFilter) {
415 fRecordingCanvas->setDrawFilter(drawFilter)->unref();
416 }
417 }
418 }
419}
420
421bool DeferredDevice::isFreshFrame() {
422 bool ret = fFreshFrame;
423 fFreshFrame = false;
424 return ret;
425}
426
427void DeferredDevice::flushPending() {
428 if (!fPipeController.hasRecorded()) {
429 return;
430 }
431 if (fDeviceContext) {
432 fDeviceContext->prepareForDraw();
433 }
434
435 fPipeWriter.flushRecording(true);
436 fPipeController.playback();
437}
438
439void DeferredDevice::flush() {
440 this->flushPending();
441 fImmediateCanvas->flush();
442}
443
444size_t DeferredDevice::freeMemoryIfPossible(size_t bytesToFree) {
445 return fPipeWriter.freeMemoryIfPossible(bytesToFree);
446}
447
448size_t DeferredDevice::storageAllocatedForRecording() const {
449 return (fPipeController.storageAllocatedForRecording()
450 + fPipeWriter.storageAllocatedForRecording());
451}
452
453SkCanvas* DeferredDevice::recordingCanvas() {
454 size_t storageAllocated = this->storageAllocatedForRecording();
455 if (storageAllocated > fMaxRecordingStorageBytes) {
456 // First, attempt to reduce cache without flushing
457 size_t tryFree = storageAllocated - fMaxRecordingStorageBytes;
458 if (this->freeMemoryIfPossible(tryFree) < tryFree) {
459 // Flush is necessary to free more space.
460 this->flushPending();
461 // Free as much as possible to avoid oscillating around fMaxRecordingStorageBytes
462 // which could cause a high flushing frequency.
463 this->freeMemoryIfPossible(~0);
464 }
465 }
466 return fRecordingCanvas;
467}
468
469uint32_t DeferredDevice::getDeviceCapabilities() {
470 return fImmediateDevice->getDeviceCapabilities();
471}
472
473int DeferredDevice::width() const {
474 return fImmediateDevice->width();
475}
476
477int DeferredDevice::height() const {
478 return fImmediateDevice->height();
479}
480
481SkGpuRenderTarget* DeferredDevice::accessRenderTarget() {
482 this->flushPending();
483 return fImmediateDevice->accessRenderTarget();
484}
485
486void DeferredDevice::writePixels(const SkBitmap& bitmap,
487 int x, int y, SkCanvas::Config8888 config8888) {
488
489 if (x <= 0 && y <= 0 && (x + bitmap.width()) >= width() &&
490 (y + bitmap.height()) >= height()) {
491 this->contentsCleared();
492 }
493
494 if (SkBitmap::kARGB_8888_Config == bitmap.config() &&
495 SkCanvas::kNative_Premul_Config8888 != config8888 &&
496 kPMColorAlias != config8888) {
497 //Special case config: no deferral
498 this->flushPending();
499 fImmediateDevice->writePixels(bitmap, x, y, config8888);
500 return;
501 }
502
503 SkPaint paint;
504 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
505 if (shouldDrawImmediately(&bitmap, NULL)) {
506 this->flushPending();
507 fImmediateCanvas->drawSprite(bitmap, x, y, &paint);
508 } else {
509 this->recordingCanvas()->drawSprite(bitmap, x, y, &paint);
510 }
511}
512
513const SkBitmap& DeferredDevice::onAccessBitmap(SkBitmap*) {
514 this->flushPending();
515 return fImmediateDevice->accessBitmap(false);
516}
517
518SkDevice* DeferredDevice::onCreateCompatibleDevice(
519 SkBitmap::Config config, int width, int height, bool isOpaque,
520 Usage usage) {
521
522 // Save layer usage not supported, and not required by SkDeferredCanvas.
523 SkASSERT(usage != kSaveLayer_Usage);
524 // Create a compatible non-deferred device.
525 SkAutoTUnref<SkDevice> compatibleDevice
526 (fImmediateDevice->createCompatibleDevice(config, width, height,
527 isOpaque));
528 return SkNEW_ARGS(DeferredDevice, (compatibleDevice, fDeviceContext));
529}
530
531bool DeferredDevice::onReadPixels(
532 const SkBitmap& bitmap, int x, int y, SkCanvas::Config8888 config8888) {
533 this->flushPending();
534 return fImmediateCanvas->readPixels(const_cast<SkBitmap*>(&bitmap),
535 x, y, config8888);
536}
537
538
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000539SkDeferredCanvas::SkDeferredCanvas() {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000540 this->init();
junov@google.com4370aed2012-01-18 16:21:08 +0000541}
542
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000543SkDeferredCanvas::SkDeferredCanvas(SkDevice* device) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000544 this->init();
545 this->setDevice(device);
junov@google.com4370aed2012-01-18 16:21:08 +0000546}
547
548SkDeferredCanvas::SkDeferredCanvas(SkDevice* device,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000549 DeviceContext* deviceContext) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000550 this->init();
551 this->setDevice(device);
552 this->setDeviceContext(deviceContext);
junov@google.com4370aed2012-01-18 16:21:08 +0000553}
554
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000555void SkDeferredCanvas::init() {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000556 fDeferredDrawing = true; // On by default
junov@google.com4370aed2012-01-18 16:21:08 +0000557}
558
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000559void SkDeferredCanvas::setMaxRecordingStorage(size_t maxStorage) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000560 this->validate();
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000561 this->getDeferredDevice()->setMaxRecordingStorage(maxStorage);
562}
563
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000564size_t SkDeferredCanvas::storageAllocatedForRecording() const {
565 return this->getDeferredDevice()->storageAllocatedForRecording();
566}
567
568size_t SkDeferredCanvas::freeMemoryIfPossible(size_t bytesToFree) {
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000569 return this->getDeferredDevice()->freeMemoryIfPossible(bytesToFree);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000570}
571
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000572void SkDeferredCanvas::validate() const {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000573 SkASSERT(this->getDevice());
junov@google.com4370aed2012-01-18 16:21:08 +0000574}
575
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000576SkCanvas* SkDeferredCanvas::drawingCanvas() const {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000577 this->validate();
578 return fDeferredDrawing ? this->getDeferredDevice()->recordingCanvas() :
579 this->getDeferredDevice()->immediateCanvas();
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000580}
581
junov@chromium.org88e29142012-08-07 16:48:22 +0000582SkCanvas* SkDeferredCanvas::immediateCanvas() const {
583 this->validate();
584 return this->getDeferredDevice()->immediateCanvas();
585}
586
587DeferredDevice* SkDeferredCanvas::getDeferredDevice() const {
588 return static_cast<DeferredDevice*>(this->getDevice());
junov@google.com4370aed2012-01-18 16:21:08 +0000589}
590
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000591void SkDeferredCanvas::setDeferredDrawing(bool val) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000592 this->validate(); // Must set device before calling this method
junov@google.com4370aed2012-01-18 16:21:08 +0000593 if (val != fDeferredDrawing) {
594 if (fDeferredDrawing) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000595 // Going live.
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000596 this->getDeferredDevice()->flushPending();
junov@google.com4370aed2012-01-18 16:21:08 +0000597 }
598 fDeferredDrawing = val;
599 }
600}
601
junov@chromium.org88e29142012-08-07 16:48:22 +0000602bool SkDeferredCanvas::isDeferredDrawing() const {
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +0000603 return fDeferredDrawing;
604}
605
junov@chromium.org88e29142012-08-07 16:48:22 +0000606bool SkDeferredCanvas::isFreshFrame() const {
607 return this->getDeferredDevice()->isFreshFrame();
608}
609
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000610SkDeferredCanvas::~SkDeferredCanvas() {
junov@google.com4370aed2012-01-18 16:21:08 +0000611}
612
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000613SkDevice* SkDeferredCanvas::setDevice(SkDevice* device) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000614 this->INHERITED::setDevice(SkNEW_ARGS(DeferredDevice, (device)))->unref();
junov@google.com4370aed2012-01-18 16:21:08 +0000615 return device;
616}
617
618SkDeferredCanvas::DeviceContext* SkDeferredCanvas::setDeviceContext(
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000619 DeviceContext* deviceContext) {
620
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000621 DeferredDevice* deferredDevice = this->getDeferredDevice();
junov@google.com4370aed2012-01-18 16:21:08 +0000622 SkASSERT(deferredDevice);
623 if (deferredDevice) {
624 deferredDevice->setDeviceContext(deviceContext);
625 }
626 return deviceContext;
627}
628
629bool SkDeferredCanvas::isFullFrame(const SkRect* rect,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000630 const SkPaint* paint) const {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000631 SkCanvas* canvas = this->drawingCanvas();
632 SkISize canvasSize = this->getDeviceSize();
junov@google.com4370aed2012-01-18 16:21:08 +0000633 if (rect) {
634 if (!canvas->getTotalMatrix().rectStaysRect()) {
635 return false; // conservative
636 }
637
638 SkRect transformedRect;
639 canvas->getTotalMatrix().mapRect(&transformedRect, *rect);
640
641 if (paint) {
642 SkPaint::Style paintStyle = paint->getStyle();
643 if (!(paintStyle == SkPaint::kFill_Style ||
644 paintStyle == SkPaint::kStrokeAndFill_Style)) {
645 return false;
646 }
647 if (paint->getMaskFilter() || paint->getLooper()
648 || paint->getPathEffect() || paint->getImageFilter()) {
649 return false; // conservative
650 }
651 }
652
653 // The following test holds with AA enabled, and is conservative
654 // by a 0.5 pixel margin with AA disabled
junov@chromium.orgb1e218e2012-02-13 22:27:58 +0000655 if (transformedRect.fLeft > SkIntToScalar(0) ||
656 transformedRect.fTop > SkIntToScalar(0) ||
657 transformedRect.fRight < SkIntToScalar(canvasSize.fWidth) ||
658 transformedRect.fBottom < SkIntToScalar(canvasSize.fHeight)) {
junov@google.com4370aed2012-01-18 16:21:08 +0000659 return false;
660 }
661 }
662
663 switch (canvas->getClipType()) {
664 case SkCanvas::kRect_ClipType :
665 {
666 SkIRect bounds;
667 canvas->getClipDeviceBounds(&bounds);
668 if (bounds.fLeft > 0 || bounds.fTop > 0 ||
669 bounds.fRight < canvasSize.fWidth ||
670 bounds.fBottom < canvasSize.fHeight)
671 return false;
672 }
673 break;
674 case SkCanvas::kComplex_ClipType :
675 return false; // conservative
676 case SkCanvas::kEmpty_ClipType:
677 default:
678 break;
679 };
680
681 return true;
682}
683
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000684int SkDeferredCanvas::save(SaveFlags flags) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000685 this->drawingCanvas()->save(flags);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000686 return this->INHERITED::save(flags);
junov@google.com4370aed2012-01-18 16:21:08 +0000687}
688
689int SkDeferredCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000690 SaveFlags flags) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000691 this->drawingCanvas()->saveLayer(bounds, paint, flags);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000692 int count = this->INHERITED::save(flags);
693 this->clipRectBounds(bounds, flags, NULL);
694 return count;
junov@google.com4370aed2012-01-18 16:21:08 +0000695}
696
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000697void SkDeferredCanvas::restore() {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000698 this->drawingCanvas()->restore();
junov@chromium.orga907ac32012-02-24 21:54:07 +0000699 this->INHERITED::restore();
junov@google.com4370aed2012-01-18 16:21:08 +0000700}
701
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000702bool SkDeferredCanvas::isDrawingToLayer() const {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000703 return this->drawingCanvas()->isDrawingToLayer();
junov@google.com4370aed2012-01-18 16:21:08 +0000704}
705
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000706bool SkDeferredCanvas::translate(SkScalar dx, SkScalar dy) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000707 this->drawingCanvas()->translate(dx, dy);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000708 return this->INHERITED::translate(dx, dy);
junov@google.com4370aed2012-01-18 16:21:08 +0000709}
710
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000711bool SkDeferredCanvas::scale(SkScalar sx, SkScalar sy) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000712 this->drawingCanvas()->scale(sx, sy);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000713 return this->INHERITED::scale(sx, sy);
junov@google.com4370aed2012-01-18 16:21:08 +0000714}
715
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000716bool SkDeferredCanvas::rotate(SkScalar degrees) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000717 this->drawingCanvas()->rotate(degrees);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000718 return this->INHERITED::rotate(degrees);
junov@google.com4370aed2012-01-18 16:21:08 +0000719}
720
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000721bool SkDeferredCanvas::skew(SkScalar sx, SkScalar sy) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000722 this->drawingCanvas()->skew(sx, sy);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000723 return this->INHERITED::skew(sx, sy);
junov@google.com4370aed2012-01-18 16:21:08 +0000724}
725
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000726bool SkDeferredCanvas::concat(const SkMatrix& matrix) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000727 this->drawingCanvas()->concat(matrix);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000728 return this->INHERITED::concat(matrix);
junov@google.com4370aed2012-01-18 16:21:08 +0000729}
730
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000731void SkDeferredCanvas::setMatrix(const SkMatrix& matrix) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000732 this->drawingCanvas()->setMatrix(matrix);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000733 this->INHERITED::setMatrix(matrix);
junov@google.com4370aed2012-01-18 16:21:08 +0000734}
735
736bool SkDeferredCanvas::clipRect(const SkRect& rect,
737 SkRegion::Op op,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000738 bool doAntiAlias) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000739 this->drawingCanvas()->clipRect(rect, op, doAntiAlias);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000740 return this->INHERITED::clipRect(rect, op, doAntiAlias);
junov@google.com4370aed2012-01-18 16:21:08 +0000741}
742
743bool SkDeferredCanvas::clipPath(const SkPath& path,
744 SkRegion::Op op,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000745 bool doAntiAlias) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000746 this->drawingCanvas()->clipPath(path, op, doAntiAlias);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000747 return this->INHERITED::clipPath(path, op, doAntiAlias);
junov@google.com4370aed2012-01-18 16:21:08 +0000748}
749
750bool SkDeferredCanvas::clipRegion(const SkRegion& deviceRgn,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000751 SkRegion::Op op) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000752 this->drawingCanvas()->clipRegion(deviceRgn, op);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000753 return this->INHERITED::clipRegion(deviceRgn, op);
junov@google.com4370aed2012-01-18 16:21:08 +0000754}
755
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000756void SkDeferredCanvas::clear(SkColor color) {
junov@google.com4370aed2012-01-18 16:21:08 +0000757 // purge pending commands
758 if (fDeferredDrawing) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000759 this->getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000760 }
761
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000762 this->drawingCanvas()->clear(color);
junov@google.com4370aed2012-01-18 16:21:08 +0000763}
764
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000765void SkDeferredCanvas::drawPaint(const SkPaint& paint) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000766 if (fDeferredDrawing && this->isFullFrame(NULL, &paint) &&
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000767 isPaintOpaque(&paint)) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000768 this->getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000769 }
junov@chromium.org10f7f972012-07-31 21:01:51 +0000770 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000771 this->drawingCanvas()->drawPaint(paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000772}
773
774void SkDeferredCanvas::drawPoints(PointMode mode, size_t count,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000775 const SkPoint pts[], const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000776 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000777 this->drawingCanvas()->drawPoints(mode, count, pts, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000778}
779
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000780void SkDeferredCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000781 if (fDeferredDrawing && this->isFullFrame(&rect, &paint) &&
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000782 isPaintOpaque(&paint)) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000783 this->getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000784 }
785
junov@chromium.org10f7f972012-07-31 21:01:51 +0000786 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000787 this->drawingCanvas()->drawRect(rect, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000788}
789
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000790void SkDeferredCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000791 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000792 this->drawingCanvas()->drawPath(path, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000793}
794
795void SkDeferredCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000796 SkScalar top, const SkPaint* paint) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000797 SkRect bitmapRect = SkRect::MakeXYWH(left, top,
798 SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
junov@google.com4370aed2012-01-18 16:21:08 +0000799 if (fDeferredDrawing &&
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000800 this->isFullFrame(&bitmapRect, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000801 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000802 this->getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000803 }
804
junov@chromium.org10f7f972012-07-31 21:01:51 +0000805 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000806 this->drawingCanvas()->drawBitmap(bitmap, left, top, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000807}
808
809void SkDeferredCanvas::drawBitmapRect(const SkBitmap& bitmap,
810 const SkIRect* src,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000811 const SkRect& dst,
812 const SkPaint* paint) {
junov@google.com4370aed2012-01-18 16:21:08 +0000813 if (fDeferredDrawing &&
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000814 this->isFullFrame(&dst, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000815 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000816 this->getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000817 }
818
junov@chromium.org10f7f972012-07-31 21:01:51 +0000819 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000820 this->drawingCanvas()->drawBitmapRect(bitmap, src, dst, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000821}
822
823
824void SkDeferredCanvas::drawBitmapMatrix(const SkBitmap& bitmap,
825 const SkMatrix& m,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000826 const SkPaint* paint) {
junov@google.com4370aed2012-01-18 16:21:08 +0000827 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
828 // covers canvas entirely and transformed bitmap covers canvas entirely
junov@chromium.org10f7f972012-07-31 21:01:51 +0000829 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000830 this->drawingCanvas()->drawBitmapMatrix(bitmap, m, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000831}
832
833void SkDeferredCanvas::drawBitmapNine(const SkBitmap& bitmap,
834 const SkIRect& center, const SkRect& dst,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000835 const SkPaint* paint) {
junov@google.com4370aed2012-01-18 16:21:08 +0000836 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
837 // covers canvas entirely and dst covers canvas entirely
junov@chromium.org10f7f972012-07-31 21:01:51 +0000838 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000839 this->drawingCanvas()->drawBitmapNine(bitmap, center, dst, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000840}
841
842void SkDeferredCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000843 const SkPaint* paint) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000844 SkRect bitmapRect = SkRect::MakeXYWH(
845 SkIntToScalar(left),
846 SkIntToScalar(top),
847 SkIntToScalar(bitmap.width()),
848 SkIntToScalar(bitmap.height()));
junov@google.com4370aed2012-01-18 16:21:08 +0000849 if (fDeferredDrawing &&
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000850 this->isFullFrame(&bitmapRect, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000851 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000852 this->getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000853 }
854
junov@chromium.org10f7f972012-07-31 21:01:51 +0000855 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000856 this->drawingCanvas()->drawSprite(bitmap, left, top, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000857}
858
859void SkDeferredCanvas::drawText(const void* text, size_t byteLength,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000860 SkScalar x, SkScalar y, const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000861 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000862 this->drawingCanvas()->drawText(text, byteLength, x, y, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000863}
864
865void SkDeferredCanvas::drawPosText(const void* text, size_t byteLength,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000866 const SkPoint pos[], const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000867 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000868 this->drawingCanvas()->drawPosText(text, byteLength, pos, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000869}
870
871void SkDeferredCanvas::drawPosTextH(const void* text, size_t byteLength,
872 const SkScalar xpos[], SkScalar constY,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000873 const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000874 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000875 this->drawingCanvas()->drawPosTextH(text, byteLength, xpos, constY, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000876}
877
878void SkDeferredCanvas::drawTextOnPath(const void* text, size_t byteLength,
879 const SkPath& path,
880 const SkMatrix* matrix,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000881 const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000882 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000883 this->drawingCanvas()->drawTextOnPath(text, byteLength, path, matrix, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000884}
885
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000886void SkDeferredCanvas::drawPicture(SkPicture& picture) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000887 this->drawingCanvas()->drawPicture(picture);
junov@google.com4370aed2012-01-18 16:21:08 +0000888}
889
890void SkDeferredCanvas::drawVertices(VertexMode vmode, int vertexCount,
891 const SkPoint vertices[],
892 const SkPoint texs[],
893 const SkColor colors[], SkXfermode* xmode,
894 const uint16_t indices[], int indexCount,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000895 const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000896 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000897 this->drawingCanvas()->drawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
898 indices, indexCount, paint);
junov@google.com4370aed2012-01-18 16:21:08 +0000899}
900
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000901SkBounder* SkDeferredCanvas::setBounder(SkBounder* bounder) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000902 this->drawingCanvas()->setBounder(bounder);
903 return this->INHERITED::setBounder(bounder);
junov@google.com4370aed2012-01-18 16:21:08 +0000904}
905
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000906SkDrawFilter* SkDeferredCanvas::setDrawFilter(SkDrawFilter* filter) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000907 this->drawingCanvas()->setDrawFilter(filter);
908 return this->INHERITED::setDrawFilter(filter);
junov@google.com4370aed2012-01-18 16:21:08 +0000909}
910
911SkCanvas* SkDeferredCanvas::canvasForDrawIter() {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000912 return this->drawingCanvas();
junov@google.com4370aed2012-01-18 16:21:08 +0000913}