blob: c66e09cfae6c9a5bc9368656bf74e21644a8ef9e [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.org9ed02b92012-08-14 13:36:26 +000019SK_DEFINE_INST_COUNT(SkDeferredCanvas::NotificationClient)
reed@google.com563a3b42012-06-26 19:24:50 +000020
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,
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000236 SkDeferredCanvas::NotificationClient* notificationClient = NULL);
junov@chromium.org88e29142012-08-07 16:48:22 +0000237 ~DeferredDevice();
238
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000239 void setNotificationClient(SkDeferredCanvas::NotificationClient* notificationClient);
junov@chromium.org88e29142012-08-07 16:48:22 +0000240 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);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000249 void recordedDrawCommand();
junov@chromium.org88e29142012-08-07 16:48:22 +0000250
251 virtual uint32_t getDeviceCapabilities() SK_OVERRIDE;
252 virtual int width() const SK_OVERRIDE;
253 virtual int height() const SK_OVERRIDE;
254 virtual SkGpuRenderTarget* accessRenderTarget() SK_OVERRIDE;
255
256 virtual SkDevice* onCreateCompatibleDevice(SkBitmap::Config config,
257 int width, int height,
258 bool isOpaque,
259 Usage usage) SK_OVERRIDE;
260
261 virtual void writePixels(const SkBitmap& bitmap, int x, int y,
262 SkCanvas::Config8888 config8888) SK_OVERRIDE;
263
264protected:
265 virtual const SkBitmap& onAccessBitmap(SkBitmap*) SK_OVERRIDE;
266 virtual bool onReadPixels(const SkBitmap& bitmap,
267 int x, int y,
268 SkCanvas::Config8888 config8888) SK_OVERRIDE;
269
270 // The following methods are no-ops on a deferred device
271 virtual bool filterTextFlags(const SkPaint& paint, TextFlags*)
272 SK_OVERRIDE
273 {return false;}
274 virtual void setMatrixClip(const SkMatrix&, const SkRegion&,
275 const SkClipStack&) SK_OVERRIDE
276 {}
277
278 // None of the following drawing methods should ever get called on the
279 // deferred device
280 virtual void clear(SkColor color)
281 {SkASSERT(0);}
282 virtual void drawPaint(const SkDraw&, const SkPaint& paint)
283 {SkASSERT(0);}
284 virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode,
285 size_t count, const SkPoint[],
286 const SkPaint& paint)
287 {SkASSERT(0);}
288 virtual void drawRect(const SkDraw&, const SkRect& r,
289 const SkPaint& paint)
290 {SkASSERT(0);}
291 virtual void drawPath(const SkDraw&, const SkPath& path,
292 const SkPaint& paint,
293 const SkMatrix* prePathMatrix = NULL,
294 bool pathIsMutable = false)
295 {SkASSERT(0);}
296 virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap,
297 const SkIRect* srcRectOrNull,
298 const SkMatrix& matrix, const SkPaint& paint)
299 {SkASSERT(0);}
300 virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap,
301 int x, int y, const SkPaint& paint)
302 {SkASSERT(0);}
303 virtual void drawText(const SkDraw&, const void* text, size_t len,
304 SkScalar x, SkScalar y, const SkPaint& paint)
305 {SkASSERT(0);}
306 virtual void drawPosText(const SkDraw&, const void* text, size_t len,
307 const SkScalar pos[], SkScalar constY,
308 int scalarsPerPos, const SkPaint& paint)
309 {SkASSERT(0);}
310 virtual void drawTextOnPath(const SkDraw&, const void* text,
311 size_t len, const SkPath& path,
312 const SkMatrix* matrix,
313 const SkPaint& paint)
314 {SkASSERT(0);}
315 virtual void drawPosTextOnPath(const SkDraw& draw, const void* text,
316 size_t len, const SkPoint pos[],
317 const SkPaint& paint,
318 const SkPath& path,
319 const SkMatrix* matrix)
320 {SkASSERT(0);}
321 virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode,
322 int vertexCount, const SkPoint verts[],
323 const SkPoint texs[], const SkColor colors[],
324 SkXfermode* xmode, const uint16_t indices[],
325 int indexCount, const SkPaint& paint)
326 {SkASSERT(0);}
327 virtual void drawDevice(const SkDraw&, SkDevice*, int x, int y,
328 const SkPaint&)
329 {SkASSERT(0);}
330private:
331 virtual void flush();
332
333 void endRecording();
334 void beginRecording();
335
336 DeferredPipeController fPipeController;
337 SkGPipeWriter fPipeWriter;
338 SkDevice* fImmediateDevice;
339 SkCanvas* fImmediateCanvas;
340 SkCanvas* fRecordingCanvas;
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000341 SkDeferredCanvas::NotificationClient* fNotificationClient;
junov@chromium.org88e29142012-08-07 16:48:22 +0000342 bool fFreshFrame;
343 size_t fMaxRecordingStorageBytes;
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000344 size_t fPreviousStorageAllocated;
junov@chromium.org88e29142012-08-07 16:48:22 +0000345};
346
347DeferredDevice::DeferredDevice(
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000348 SkDevice* immediateDevice, SkDeferredCanvas::NotificationClient* notificationClient) :
junov@chromium.org88e29142012-08-07 16:48:22 +0000349 SkDevice(SkBitmap::kNo_Config, immediateDevice->width(),
350 immediateDevice->height(), immediateDevice->isOpaque())
junov@chromium.orga8db8fe2012-08-15 19:49:22 +0000351 , fRecordingCanvas(NULL)
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000352 , fFreshFrame(true)
353 , fPreviousStorageAllocated(0){
junov@chromium.org88e29142012-08-07 16:48:22 +0000354
355 fMaxRecordingStorageBytes = kDefaultMaxRecordingStorageBytes;
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000356 fNotificationClient = notificationClient;
357 SkSafeRef(fNotificationClient);
junov@chromium.org88e29142012-08-07 16:48:22 +0000358 fImmediateDevice = immediateDevice; // ref counted via fImmediateCanvas
359 fImmediateCanvas = SkNEW_ARGS(SkCanvas, (fImmediateDevice));
360 fPipeController.setPlaybackCanvas(fImmediateCanvas);
361 this->beginRecording();
362}
363
364DeferredDevice::~DeferredDevice() {
365 this->flushPending();
366 SkSafeUnref(fImmediateCanvas);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000367 SkSafeUnref(fNotificationClient);
junov@chromium.org88e29142012-08-07 16:48:22 +0000368}
369
370void DeferredDevice::setMaxRecordingStorage(size_t maxStorage) {
371 fMaxRecordingStorageBytes = maxStorage;
372 this->recordingCanvas(); // Accessing the recording canvas applies the new limit.
373}
374
375void DeferredDevice::endRecording() {
376 fPipeWriter.endRecording();
377 fPipeController.reset();
378 fRecordingCanvas = NULL;
379}
380
381void DeferredDevice::beginRecording() {
junov@chromium.orga8db8fe2012-08-15 19:49:22 +0000382 SkASSERT(NULL == fRecordingCanvas);
383 fRecordingCanvas = fPipeWriter.startRecording(&fPipeController, 0,
384 fImmediateDevice->width(), fImmediateDevice->height());
junov@chromium.org88e29142012-08-07 16:48:22 +0000385}
386
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000387void DeferredDevice::setNotificationClient(
388 SkDeferredCanvas::NotificationClient* notificationClient) {
389 SkRefCnt_SafeAssign(fNotificationClient, notificationClient);
junov@chromium.org88e29142012-08-07 16:48:22 +0000390}
391
392void DeferredDevice::contentsCleared() {
393 if (!fRecordingCanvas->isDrawingToLayer()) {
394 fFreshFrame = true;
395
396 // TODO: find a way to transfer the state stack and layers
397 // to the new recording canvas. For now, purging only works
junov@chromium.orga8db8fe2012-08-15 19:49:22 +0000398 // with an empty stack. A save count of 1 means an empty stack.
399 SkASSERT(fRecordingCanvas->getSaveCount() >= 1);
400 if (fRecordingCanvas->getSaveCount() == 1) {
junov@chromium.org88e29142012-08-07 16:48:22 +0000401
402 // Save state that is trashed by the purge
403 SkDrawFilter* drawFilter = fRecordingCanvas->getDrawFilter();
404 SkSafeRef(drawFilter); // So that it survives the purge
405 SkMatrix matrix = fRecordingCanvas->getTotalMatrix();
406 SkRegion clipRegion = fRecordingCanvas->getTotalClip();
407
408 // beginRecording creates a new recording canvas and discards the
409 // old one, hence purging deferred draw ops.
410 this->endRecording();
411 this->beginRecording();
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000412 fPreviousStorageAllocated = storageAllocatedForRecording();
junov@chromium.org88e29142012-08-07 16:48:22 +0000413
414 // Restore pre-purge state
415 if (!clipRegion.isEmpty()) {
416 fRecordingCanvas->clipRegion(clipRegion,
417 SkRegion::kReplace_Op);
418 }
419 if (!matrix.isIdentity()) {
420 fRecordingCanvas->setMatrix(matrix);
421 }
422 if (drawFilter) {
423 fRecordingCanvas->setDrawFilter(drawFilter)->unref();
424 }
425 }
426 }
427}
428
429bool DeferredDevice::isFreshFrame() {
430 bool ret = fFreshFrame;
431 fFreshFrame = false;
432 return ret;
433}
434
435void DeferredDevice::flushPending() {
436 if (!fPipeController.hasRecorded()) {
437 return;
438 }
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000439 if (fNotificationClient) {
440 fNotificationClient->prepareForDraw();
junov@chromium.org88e29142012-08-07 16:48:22 +0000441 }
junov@chromium.org88e29142012-08-07 16:48:22 +0000442 fPipeWriter.flushRecording(true);
443 fPipeController.playback();
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000444 if (fNotificationClient) {
445 fNotificationClient->flushedDrawCommands();
446 }
447 fPreviousStorageAllocated = storageAllocatedForRecording();
junov@chromium.org88e29142012-08-07 16:48:22 +0000448}
449
450void DeferredDevice::flush() {
451 this->flushPending();
452 fImmediateCanvas->flush();
453}
454
455size_t DeferredDevice::freeMemoryIfPossible(size_t bytesToFree) {
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000456 size_t val = fPipeWriter.freeMemoryIfPossible(bytesToFree);
457 fPreviousStorageAllocated = storageAllocatedForRecording();
458 return val;
junov@chromium.org88e29142012-08-07 16:48:22 +0000459}
460
461size_t DeferredDevice::storageAllocatedForRecording() const {
462 return (fPipeController.storageAllocatedForRecording()
463 + fPipeWriter.storageAllocatedForRecording());
464}
465
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000466void DeferredDevice::recordedDrawCommand() {
junov@chromium.org88e29142012-08-07 16:48:22 +0000467 size_t storageAllocated = this->storageAllocatedForRecording();
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000468
junov@chromium.org88e29142012-08-07 16:48:22 +0000469 if (storageAllocated > fMaxRecordingStorageBytes) {
470 // First, attempt to reduce cache without flushing
471 size_t tryFree = storageAllocated - fMaxRecordingStorageBytes;
472 if (this->freeMemoryIfPossible(tryFree) < tryFree) {
473 // Flush is necessary to free more space.
474 this->flushPending();
475 // Free as much as possible to avoid oscillating around fMaxRecordingStorageBytes
476 // which could cause a high flushing frequency.
477 this->freeMemoryIfPossible(~0);
478 }
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000479 storageAllocated = this->storageAllocatedForRecording();
junov@chromium.org88e29142012-08-07 16:48:22 +0000480 }
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000481
482 if (fNotificationClient &&
483 storageAllocated != fPreviousStorageAllocated) {
484 fPreviousStorageAllocated = storageAllocated;
485 fNotificationClient->storageAllocatedForRecordingChanged(storageAllocated);
486 }
487}
488
489SkCanvas* DeferredDevice::recordingCanvas() {
junov@chromium.org88e29142012-08-07 16:48:22 +0000490 return fRecordingCanvas;
491}
492
493uint32_t DeferredDevice::getDeviceCapabilities() {
494 return fImmediateDevice->getDeviceCapabilities();
495}
496
497int DeferredDevice::width() const {
498 return fImmediateDevice->width();
499}
500
501int DeferredDevice::height() const {
502 return fImmediateDevice->height();
503}
504
505SkGpuRenderTarget* DeferredDevice::accessRenderTarget() {
506 this->flushPending();
507 return fImmediateDevice->accessRenderTarget();
508}
509
510void DeferredDevice::writePixels(const SkBitmap& bitmap,
511 int x, int y, SkCanvas::Config8888 config8888) {
512
513 if (x <= 0 && y <= 0 && (x + bitmap.width()) >= width() &&
514 (y + bitmap.height()) >= height()) {
515 this->contentsCleared();
516 }
517
518 if (SkBitmap::kARGB_8888_Config == bitmap.config() &&
519 SkCanvas::kNative_Premul_Config8888 != config8888 &&
520 kPMColorAlias != config8888) {
521 //Special case config: no deferral
522 this->flushPending();
523 fImmediateDevice->writePixels(bitmap, x, y, config8888);
524 return;
525 }
526
527 SkPaint paint;
528 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
529 if (shouldDrawImmediately(&bitmap, NULL)) {
530 this->flushPending();
531 fImmediateCanvas->drawSprite(bitmap, x, y, &paint);
532 } else {
533 this->recordingCanvas()->drawSprite(bitmap, x, y, &paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000534 this->recordedDrawCommand();
535
junov@chromium.org88e29142012-08-07 16:48:22 +0000536 }
537}
538
539const SkBitmap& DeferredDevice::onAccessBitmap(SkBitmap*) {
540 this->flushPending();
541 return fImmediateDevice->accessBitmap(false);
542}
543
544SkDevice* DeferredDevice::onCreateCompatibleDevice(
545 SkBitmap::Config config, int width, int height, bool isOpaque,
546 Usage usage) {
547
548 // Save layer usage not supported, and not required by SkDeferredCanvas.
549 SkASSERT(usage != kSaveLayer_Usage);
550 // Create a compatible non-deferred device.
551 SkAutoTUnref<SkDevice> compatibleDevice
552 (fImmediateDevice->createCompatibleDevice(config, width, height,
553 isOpaque));
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000554 return SkNEW_ARGS(DeferredDevice, (compatibleDevice, fNotificationClient));
junov@chromium.org88e29142012-08-07 16:48:22 +0000555}
556
557bool DeferredDevice::onReadPixels(
558 const SkBitmap& bitmap, int x, int y, SkCanvas::Config8888 config8888) {
559 this->flushPending();
560 return fImmediateCanvas->readPixels(const_cast<SkBitmap*>(&bitmap),
561 x, y, config8888);
562}
563
564
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000565SkDeferredCanvas::SkDeferredCanvas() {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000566 this->init();
junov@google.com4370aed2012-01-18 16:21:08 +0000567}
568
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000569SkDeferredCanvas::SkDeferredCanvas(SkDevice* device) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000570 this->init();
571 this->setDevice(device);
junov@google.com4370aed2012-01-18 16:21:08 +0000572}
573
574SkDeferredCanvas::SkDeferredCanvas(SkDevice* device,
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000575 NotificationClient* notificationClient) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000576 this->init();
577 this->setDevice(device);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000578 this->setNotificationClient(notificationClient);
junov@google.com4370aed2012-01-18 16:21:08 +0000579}
580
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000581void SkDeferredCanvas::init() {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000582 fDeferredDrawing = true; // On by default
junov@google.com4370aed2012-01-18 16:21:08 +0000583}
584
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000585void SkDeferredCanvas::setMaxRecordingStorage(size_t maxStorage) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000586 this->validate();
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000587 this->getDeferredDevice()->setMaxRecordingStorage(maxStorage);
588}
589
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000590size_t SkDeferredCanvas::storageAllocatedForRecording() const {
591 return this->getDeferredDevice()->storageAllocatedForRecording();
592}
593
594size_t SkDeferredCanvas::freeMemoryIfPossible(size_t bytesToFree) {
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000595 return this->getDeferredDevice()->freeMemoryIfPossible(bytesToFree);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000596}
597
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000598void SkDeferredCanvas::recordedDrawCommand() {
599 if (fDeferredDrawing) {
600 this->getDeferredDevice()->recordedDrawCommand();
601 }
602}
603
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000604void SkDeferredCanvas::validate() const {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000605 SkASSERT(this->getDevice());
junov@google.com4370aed2012-01-18 16:21:08 +0000606}
607
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000608SkCanvas* SkDeferredCanvas::drawingCanvas() const {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000609 this->validate();
610 return fDeferredDrawing ? this->getDeferredDevice()->recordingCanvas() :
611 this->getDeferredDevice()->immediateCanvas();
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000612}
613
junov@chromium.org88e29142012-08-07 16:48:22 +0000614SkCanvas* SkDeferredCanvas::immediateCanvas() const {
615 this->validate();
616 return this->getDeferredDevice()->immediateCanvas();
617}
618
619DeferredDevice* SkDeferredCanvas::getDeferredDevice() const {
620 return static_cast<DeferredDevice*>(this->getDevice());
junov@google.com4370aed2012-01-18 16:21:08 +0000621}
622
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000623void SkDeferredCanvas::setDeferredDrawing(bool val) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000624 this->validate(); // Must set device before calling this method
junov@google.com4370aed2012-01-18 16:21:08 +0000625 if (val != fDeferredDrawing) {
626 if (fDeferredDrawing) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000627 // Going live.
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000628 this->getDeferredDevice()->flushPending();
junov@google.com4370aed2012-01-18 16:21:08 +0000629 }
630 fDeferredDrawing = val;
631 }
632}
633
junov@chromium.org88e29142012-08-07 16:48:22 +0000634bool SkDeferredCanvas::isDeferredDrawing() const {
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +0000635 return fDeferredDrawing;
636}
637
junov@chromium.org88e29142012-08-07 16:48:22 +0000638bool SkDeferredCanvas::isFreshFrame() const {
639 return this->getDeferredDevice()->isFreshFrame();
640}
641
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000642SkDeferredCanvas::~SkDeferredCanvas() {
junov@google.com4370aed2012-01-18 16:21:08 +0000643}
644
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000645SkDevice* SkDeferredCanvas::setDevice(SkDevice* device) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000646 this->INHERITED::setDevice(SkNEW_ARGS(DeferredDevice, (device)))->unref();
junov@google.com4370aed2012-01-18 16:21:08 +0000647 return device;
648}
649
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000650SkDeferredCanvas::NotificationClient* SkDeferredCanvas::setNotificationClient(
651 NotificationClient* notificationClient) {
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000652
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000653 DeferredDevice* deferredDevice = this->getDeferredDevice();
junov@google.com4370aed2012-01-18 16:21:08 +0000654 SkASSERT(deferredDevice);
655 if (deferredDevice) {
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000656 deferredDevice->setNotificationClient(notificationClient);
junov@google.com4370aed2012-01-18 16:21:08 +0000657 }
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000658 return notificationClient;
junov@google.com4370aed2012-01-18 16:21:08 +0000659}
660
661bool SkDeferredCanvas::isFullFrame(const SkRect* rect,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000662 const SkPaint* paint) const {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000663 SkCanvas* canvas = this->drawingCanvas();
664 SkISize canvasSize = this->getDeviceSize();
junov@google.com4370aed2012-01-18 16:21:08 +0000665 if (rect) {
666 if (!canvas->getTotalMatrix().rectStaysRect()) {
667 return false; // conservative
668 }
669
670 SkRect transformedRect;
671 canvas->getTotalMatrix().mapRect(&transformedRect, *rect);
672
673 if (paint) {
674 SkPaint::Style paintStyle = paint->getStyle();
675 if (!(paintStyle == SkPaint::kFill_Style ||
676 paintStyle == SkPaint::kStrokeAndFill_Style)) {
677 return false;
678 }
679 if (paint->getMaskFilter() || paint->getLooper()
680 || paint->getPathEffect() || paint->getImageFilter()) {
681 return false; // conservative
682 }
683 }
684
685 // The following test holds with AA enabled, and is conservative
686 // by a 0.5 pixel margin with AA disabled
junov@chromium.orgb1e218e2012-02-13 22:27:58 +0000687 if (transformedRect.fLeft > SkIntToScalar(0) ||
688 transformedRect.fTop > SkIntToScalar(0) ||
689 transformedRect.fRight < SkIntToScalar(canvasSize.fWidth) ||
690 transformedRect.fBottom < SkIntToScalar(canvasSize.fHeight)) {
junov@google.com4370aed2012-01-18 16:21:08 +0000691 return false;
692 }
693 }
694
695 switch (canvas->getClipType()) {
696 case SkCanvas::kRect_ClipType :
697 {
698 SkIRect bounds;
699 canvas->getClipDeviceBounds(&bounds);
700 if (bounds.fLeft > 0 || bounds.fTop > 0 ||
701 bounds.fRight < canvasSize.fWidth ||
702 bounds.fBottom < canvasSize.fHeight)
703 return false;
704 }
705 break;
706 case SkCanvas::kComplex_ClipType :
707 return false; // conservative
708 case SkCanvas::kEmpty_ClipType:
709 default:
710 break;
711 };
712
713 return true;
714}
715
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000716int SkDeferredCanvas::save(SaveFlags flags) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000717 this->drawingCanvas()->save(flags);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000718 int val = this->INHERITED::save(flags);
719 this->recordedDrawCommand();
720
721 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000722}
723
724int SkDeferredCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000725 SaveFlags flags) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000726 this->drawingCanvas()->saveLayer(bounds, paint, flags);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000727 int count = this->INHERITED::save(flags);
728 this->clipRectBounds(bounds, flags, NULL);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000729 this->recordedDrawCommand();
730
junov@chromium.orga907ac32012-02-24 21:54:07 +0000731 return count;
junov@google.com4370aed2012-01-18 16:21:08 +0000732}
733
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000734void SkDeferredCanvas::restore() {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000735 this->drawingCanvas()->restore();
junov@chromium.orga907ac32012-02-24 21:54:07 +0000736 this->INHERITED::restore();
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000737 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000738}
739
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000740bool SkDeferredCanvas::isDrawingToLayer() const {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000741 return this->drawingCanvas()->isDrawingToLayer();
junov@google.com4370aed2012-01-18 16:21:08 +0000742}
743
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000744bool SkDeferredCanvas::translate(SkScalar dx, SkScalar dy) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000745 this->drawingCanvas()->translate(dx, dy);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000746 bool val = this->INHERITED::translate(dx, dy);
747 this->recordedDrawCommand();
748 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000749}
750
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000751bool SkDeferredCanvas::scale(SkScalar sx, SkScalar sy) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000752 this->drawingCanvas()->scale(sx, sy);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000753 bool val = this->INHERITED::scale(sx, sy);
754 this->recordedDrawCommand();
755 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000756}
757
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000758bool SkDeferredCanvas::rotate(SkScalar degrees) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000759 this->drawingCanvas()->rotate(degrees);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000760 bool val = this->INHERITED::rotate(degrees);
761 this->recordedDrawCommand();
762 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000763}
764
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000765bool SkDeferredCanvas::skew(SkScalar sx, SkScalar sy) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000766 this->drawingCanvas()->skew(sx, sy);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000767 bool val = this->INHERITED::skew(sx, sy);
768 this->recordedDrawCommand();
769 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000770}
771
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000772bool SkDeferredCanvas::concat(const SkMatrix& matrix) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000773 this->drawingCanvas()->concat(matrix);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000774 bool val = this->INHERITED::concat(matrix);
775 this->recordedDrawCommand();
776 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000777}
778
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000779void SkDeferredCanvas::setMatrix(const SkMatrix& matrix) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000780 this->drawingCanvas()->setMatrix(matrix);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000781 this->INHERITED::setMatrix(matrix);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000782 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000783}
784
785bool SkDeferredCanvas::clipRect(const SkRect& rect,
786 SkRegion::Op op,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000787 bool doAntiAlias) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000788 this->drawingCanvas()->clipRect(rect, op, doAntiAlias);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000789 bool val = this->INHERITED::clipRect(rect, op, doAntiAlias);
790 this->recordedDrawCommand();
791 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000792}
793
794bool SkDeferredCanvas::clipPath(const SkPath& path,
795 SkRegion::Op op,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000796 bool doAntiAlias) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000797 this->drawingCanvas()->clipPath(path, op, doAntiAlias);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000798 bool val = this->INHERITED::clipPath(path, op, doAntiAlias);
799 this->recordedDrawCommand();
800 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000801}
802
803bool SkDeferredCanvas::clipRegion(const SkRegion& deviceRgn,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000804 SkRegion::Op op) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000805 this->drawingCanvas()->clipRegion(deviceRgn, op);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000806 bool val = this->INHERITED::clipRegion(deviceRgn, op);
807 this->recordedDrawCommand();
808 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000809}
810
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000811void SkDeferredCanvas::clear(SkColor color) {
junov@google.com4370aed2012-01-18 16:21:08 +0000812 // purge pending commands
813 if (fDeferredDrawing) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000814 this->getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000815 }
816
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000817 this->drawingCanvas()->clear(color);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000818 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000819}
820
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000821void SkDeferredCanvas::drawPaint(const SkPaint& paint) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000822 if (fDeferredDrawing && this->isFullFrame(NULL, &paint) &&
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000823 isPaintOpaque(&paint)) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000824 this->getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000825 }
junov@chromium.org10f7f972012-07-31 21:01:51 +0000826 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000827 this->drawingCanvas()->drawPaint(paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000828 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000829}
830
831void SkDeferredCanvas::drawPoints(PointMode mode, size_t count,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000832 const SkPoint pts[], const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000833 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000834 this->drawingCanvas()->drawPoints(mode, count, pts, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000835 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000836}
837
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000838void SkDeferredCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000839 if (fDeferredDrawing && this->isFullFrame(&rect, &paint) &&
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000840 isPaintOpaque(&paint)) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000841 this->getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000842 }
843
junov@chromium.org10f7f972012-07-31 21:01:51 +0000844 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000845 this->drawingCanvas()->drawRect(rect, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000846 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000847}
848
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000849void SkDeferredCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000850 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000851 this->drawingCanvas()->drawPath(path, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000852 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000853}
854
855void SkDeferredCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000856 SkScalar top, const SkPaint* paint) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000857 SkRect bitmapRect = SkRect::MakeXYWH(left, top,
858 SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
junov@google.com4370aed2012-01-18 16:21:08 +0000859 if (fDeferredDrawing &&
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000860 this->isFullFrame(&bitmapRect, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000861 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000862 this->getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000863 }
864
junov@chromium.org10f7f972012-07-31 21:01:51 +0000865 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000866 this->drawingCanvas()->drawBitmap(bitmap, left, top, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000867 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000868}
869
870void SkDeferredCanvas::drawBitmapRect(const SkBitmap& bitmap,
871 const SkIRect* src,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000872 const SkRect& dst,
873 const SkPaint* paint) {
junov@google.com4370aed2012-01-18 16:21:08 +0000874 if (fDeferredDrawing &&
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000875 this->isFullFrame(&dst, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000876 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000877 this->getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000878 }
879
junov@chromium.org10f7f972012-07-31 21:01:51 +0000880 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000881 this->drawingCanvas()->drawBitmapRect(bitmap, src, dst, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000882 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000883}
884
885
886void SkDeferredCanvas::drawBitmapMatrix(const SkBitmap& bitmap,
887 const SkMatrix& m,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000888 const SkPaint* paint) {
junov@google.com4370aed2012-01-18 16:21:08 +0000889 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
890 // covers canvas entirely and transformed bitmap covers canvas entirely
junov@chromium.org10f7f972012-07-31 21:01:51 +0000891 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000892 this->drawingCanvas()->drawBitmapMatrix(bitmap, m, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000893 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000894}
895
896void SkDeferredCanvas::drawBitmapNine(const SkBitmap& bitmap,
897 const SkIRect& center, const SkRect& dst,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000898 const SkPaint* paint) {
junov@google.com4370aed2012-01-18 16:21:08 +0000899 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
900 // covers canvas entirely and dst covers canvas entirely
junov@chromium.org10f7f972012-07-31 21:01:51 +0000901 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000902 this->drawingCanvas()->drawBitmapNine(bitmap, center, dst, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000903 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000904}
905
906void SkDeferredCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000907 const SkPaint* paint) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000908 SkRect bitmapRect = SkRect::MakeXYWH(
909 SkIntToScalar(left),
910 SkIntToScalar(top),
911 SkIntToScalar(bitmap.width()),
912 SkIntToScalar(bitmap.height()));
junov@google.com4370aed2012-01-18 16:21:08 +0000913 if (fDeferredDrawing &&
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000914 this->isFullFrame(&bitmapRect, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000915 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000916 this->getDeferredDevice()->contentsCleared();
junov@google.com4370aed2012-01-18 16:21:08 +0000917 }
918
junov@chromium.org10f7f972012-07-31 21:01:51 +0000919 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000920 this->drawingCanvas()->drawSprite(bitmap, left, top, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000921 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000922}
923
924void SkDeferredCanvas::drawText(const void* text, size_t byteLength,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000925 SkScalar x, SkScalar y, const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000926 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000927 this->drawingCanvas()->drawText(text, byteLength, x, y, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000928 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000929}
930
931void SkDeferredCanvas::drawPosText(const void* text, size_t byteLength,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000932 const SkPoint pos[], const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000933 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000934 this->drawingCanvas()->drawPosText(text, byteLength, pos, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000935 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000936}
937
938void SkDeferredCanvas::drawPosTextH(const void* text, size_t byteLength,
939 const SkScalar xpos[], SkScalar constY,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000940 const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000941 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000942 this->drawingCanvas()->drawPosTextH(text, byteLength, xpos, constY, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000943 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000944}
945
946void SkDeferredCanvas::drawTextOnPath(const void* text, size_t byteLength,
947 const SkPath& path,
948 const SkMatrix* matrix,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000949 const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000950 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000951 this->drawingCanvas()->drawTextOnPath(text, byteLength, path, matrix, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000952 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000953}
954
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000955void SkDeferredCanvas::drawPicture(SkPicture& picture) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000956 this->drawingCanvas()->drawPicture(picture);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000957 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000958}
959
960void SkDeferredCanvas::drawVertices(VertexMode vmode, int vertexCount,
961 const SkPoint vertices[],
962 const SkPoint texs[],
963 const SkColor colors[], SkXfermode* xmode,
964 const uint16_t indices[], int indexCount,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000965 const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000966 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000967 this->drawingCanvas()->drawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
968 indices, indexCount, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000969 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000970}
971
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000972SkBounder* SkDeferredCanvas::setBounder(SkBounder* bounder) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000973 this->drawingCanvas()->setBounder(bounder);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000974 this->INHERITED::setBounder(bounder);
975 this->recordedDrawCommand();
976 return bounder;
junov@google.com4370aed2012-01-18 16:21:08 +0000977}
978
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000979SkDrawFilter* SkDeferredCanvas::setDrawFilter(SkDrawFilter* filter) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000980 this->drawingCanvas()->setDrawFilter(filter);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000981 this->INHERITED::setDrawFilter(filter);
982 this->recordedDrawCommand();
983 return filter;
junov@google.com4370aed2012-01-18 16:21:08 +0000984}
985
986SkCanvas* SkDeferredCanvas::canvasForDrawIter() {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000987 return this->drawingCanvas();
junov@google.com4370aed2012-01-18 16:21:08 +0000988}