blob: ef93c9cd715fc2ac1ccbc2ac7ab22114995b7075 [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;
154 void playback();
155 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
205void DeferredPipeController::playback() {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000206
junov@chromium.org88e29142012-08-07 16:48:22 +0000207 for (int currentBlock = 0; currentBlock < fBlockList.count(); currentBlock++ ) {
208 fReader.playback(fBlockList[currentBlock].fBlock, fBlockList[currentBlock].fSize);
209 }
210 fBlockList.reset();
211
212 if (fBlock) {
213 fReader.playback(fBlock, fBytesWritten);
214 fBlock = NULL;
215 }
216
217 // Release all allocated blocks
218 fAllocator.reset();
219}
220
221void DeferredPipeController::reset() {
222 fBlockList.reset();
223 fBlock = NULL;
224 fAllocator.reset();
225}
226
227//-----------------------------------------------------------------------------
228// DeferredDevice
229//-----------------------------------------------------------------------------
230
231class DeferredDevice : public SkDevice {
232public:
233 DeferredDevice(SkDevice* immediateDevice,
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000234 SkDeferredCanvas::NotificationClient* notificationClient = NULL);
junov@chromium.org88e29142012-08-07 16:48:22 +0000235 ~DeferredDevice();
236
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000237 void setNotificationClient(SkDeferredCanvas::NotificationClient* notificationClient);
junov@chromium.org88e29142012-08-07 16:48:22 +0000238 SkCanvas* recordingCanvas();
239 SkCanvas* immediateCanvas() const {return fImmediateCanvas;}
240 SkDevice* immediateDevice() const {return fImmediateDevice;}
241 bool isFreshFrame();
242 size_t storageAllocatedForRecording() const;
243 size_t freeMemoryIfPossible(size_t bytesToFree);
junov@chromium.org0a67f962012-09-19 22:48:34 +0000244 void flushPendingCommands();
245 void skipPendingCommands();
junov@chromium.org88e29142012-08-07 16:48:22 +0000246 void setMaxRecordingStorage(size_t);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000247 void recordedDrawCommand();
junov@chromium.org88e29142012-08-07 16:48:22 +0000248
249 virtual uint32_t getDeviceCapabilities() SK_OVERRIDE;
250 virtual int width() const SK_OVERRIDE;
251 virtual int height() const SK_OVERRIDE;
252 virtual SkGpuRenderTarget* accessRenderTarget() SK_OVERRIDE;
253
254 virtual SkDevice* onCreateCompatibleDevice(SkBitmap::Config config,
255 int width, int height,
256 bool isOpaque,
257 Usage usage) SK_OVERRIDE;
258
259 virtual void writePixels(const SkBitmap& bitmap, int x, int y,
260 SkCanvas::Config8888 config8888) SK_OVERRIDE;
261
262protected:
263 virtual const SkBitmap& onAccessBitmap(SkBitmap*) SK_OVERRIDE;
264 virtual bool onReadPixels(const SkBitmap& bitmap,
265 int x, int y,
266 SkCanvas::Config8888 config8888) SK_OVERRIDE;
267
268 // The following methods are no-ops on a deferred device
269 virtual bool filterTextFlags(const SkPaint& paint, TextFlags*)
270 SK_OVERRIDE
271 {return false;}
272 virtual void setMatrixClip(const SkMatrix&, const SkRegion&,
273 const SkClipStack&) SK_OVERRIDE
274 {}
275
276 // None of the following drawing methods should ever get called on the
277 // deferred device
278 virtual void clear(SkColor color)
279 {SkASSERT(0);}
280 virtual void drawPaint(const SkDraw&, const SkPaint& paint)
281 {SkASSERT(0);}
282 virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode,
283 size_t count, const SkPoint[],
284 const SkPaint& paint)
285 {SkASSERT(0);}
286 virtual void drawRect(const SkDraw&, const SkRect& r,
287 const SkPaint& paint)
288 {SkASSERT(0);}
289 virtual void drawPath(const SkDraw&, const SkPath& path,
290 const SkPaint& paint,
291 const SkMatrix* prePathMatrix = NULL,
292 bool pathIsMutable = false)
293 {SkASSERT(0);}
294 virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap,
295 const SkIRect* srcRectOrNull,
296 const SkMatrix& matrix, const SkPaint& paint)
297 {SkASSERT(0);}
298 virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap,
299 int x, int y, const SkPaint& paint)
300 {SkASSERT(0);}
301 virtual void drawText(const SkDraw&, const void* text, size_t len,
302 SkScalar x, SkScalar y, const SkPaint& paint)
303 {SkASSERT(0);}
304 virtual void drawPosText(const SkDraw&, const void* text, size_t len,
305 const SkScalar pos[], SkScalar constY,
306 int scalarsPerPos, const SkPaint& paint)
307 {SkASSERT(0);}
308 virtual void drawTextOnPath(const SkDraw&, const void* text,
309 size_t len, const SkPath& path,
310 const SkMatrix* matrix,
311 const SkPaint& paint)
312 {SkASSERT(0);}
313 virtual void drawPosTextOnPath(const SkDraw& draw, const void* text,
314 size_t len, const SkPoint pos[],
315 const SkPaint& paint,
316 const SkPath& path,
317 const SkMatrix* matrix)
318 {SkASSERT(0);}
319 virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode,
320 int vertexCount, const SkPoint verts[],
321 const SkPoint texs[], const SkColor colors[],
322 SkXfermode* xmode, const uint16_t indices[],
323 int indexCount, const SkPaint& paint)
324 {SkASSERT(0);}
325 virtual void drawDevice(const SkDraw&, SkDevice*, int x, int y,
326 const SkPaint&)
327 {SkASSERT(0);}
328private:
329 virtual void flush();
330
331 void endRecording();
332 void beginRecording();
333
334 DeferredPipeController fPipeController;
335 SkGPipeWriter fPipeWriter;
336 SkDevice* fImmediateDevice;
337 SkCanvas* fImmediateCanvas;
338 SkCanvas* fRecordingCanvas;
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000339 SkDeferredCanvas::NotificationClient* fNotificationClient;
junov@chromium.org88e29142012-08-07 16:48:22 +0000340 bool fFreshFrame;
341 size_t fMaxRecordingStorageBytes;
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000342 size_t fPreviousStorageAllocated;
junov@chromium.org88e29142012-08-07 16:48:22 +0000343};
344
345DeferredDevice::DeferredDevice(
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000346 SkDevice* immediateDevice, SkDeferredCanvas::NotificationClient* notificationClient) :
junov@chromium.org88e29142012-08-07 16:48:22 +0000347 SkDevice(SkBitmap::kNo_Config, immediateDevice->width(),
348 immediateDevice->height(), immediateDevice->isOpaque())
junov@chromium.orga8db8fe2012-08-15 19:49:22 +0000349 , fRecordingCanvas(NULL)
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000350 , fFreshFrame(true)
351 , fPreviousStorageAllocated(0){
junov@chromium.org88e29142012-08-07 16:48:22 +0000352
353 fMaxRecordingStorageBytes = kDefaultMaxRecordingStorageBytes;
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000354 fNotificationClient = notificationClient;
junov@chromium.org88e29142012-08-07 16:48:22 +0000355 fImmediateDevice = immediateDevice; // ref counted via fImmediateCanvas
356 fImmediateCanvas = SkNEW_ARGS(SkCanvas, (fImmediateDevice));
357 fPipeController.setPlaybackCanvas(fImmediateCanvas);
358 this->beginRecording();
359}
360
361DeferredDevice::~DeferredDevice() {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000362 this->flushPendingCommands();
junov@chromium.org88e29142012-08-07 16:48:22 +0000363 SkSafeUnref(fImmediateCanvas);
junov@chromium.org88e29142012-08-07 16:48:22 +0000364}
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() {
junov@chromium.orga8db8fe2012-08-15 19:49:22 +0000378 SkASSERT(NULL == fRecordingCanvas);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000379 fRecordingCanvas = fPipeWriter.startRecording(&fPipeController, 0,
junov@chromium.orga8db8fe2012-08-15 19:49:22 +0000380 fImmediateDevice->width(), fImmediateDevice->height());
junov@chromium.org88e29142012-08-07 16:48:22 +0000381}
rmistry@google.comd6176b02012-08-23 18:14:13 +0000382
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000383void DeferredDevice::setNotificationClient(
384 SkDeferredCanvas::NotificationClient* notificationClient) {
junov@chromium.org52805482012-08-20 14:25:04 +0000385 fNotificationClient = notificationClient;
junov@chromium.org88e29142012-08-07 16:48:22 +0000386}
387
junov@chromium.org0a67f962012-09-19 22:48:34 +0000388void DeferredDevice::skipPendingCommands() {
junov@chromium.org88e29142012-08-07 16:48:22 +0000389 if (!fRecordingCanvas->isDrawingToLayer()) {
390 fFreshFrame = true;
391
392 // TODO: find a way to transfer the state stack and layers
393 // to the new recording canvas. For now, purging only works
junov@chromium.orga8db8fe2012-08-15 19:49:22 +0000394 // with an empty stack. A save count of 1 means an empty stack.
395 SkASSERT(fRecordingCanvas->getSaveCount() >= 1);
396 if (fRecordingCanvas->getSaveCount() == 1) {
junov@chromium.org88e29142012-08-07 16:48:22 +0000397
398 // Save state that is trashed by the purge
399 SkDrawFilter* drawFilter = fRecordingCanvas->getDrawFilter();
400 SkSafeRef(drawFilter); // So that it survives the purge
401 SkMatrix matrix = fRecordingCanvas->getTotalMatrix();
402 SkRegion clipRegion = fRecordingCanvas->getTotalClip();
403
404 // beginRecording creates a new recording canvas and discards the
405 // old one, hence purging deferred draw ops.
406 this->endRecording();
407 this->beginRecording();
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000408 fPreviousStorageAllocated = storageAllocatedForRecording();
junov@chromium.org88e29142012-08-07 16:48:22 +0000409
410 // Restore pre-purge state
411 if (!clipRegion.isEmpty()) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000412 fRecordingCanvas->clipRegion(clipRegion,
junov@chromium.org88e29142012-08-07 16:48:22 +0000413 SkRegion::kReplace_Op);
414 }
415 if (!matrix.isIdentity()) {
416 fRecordingCanvas->setMatrix(matrix);
417 }
418 if (drawFilter) {
419 fRecordingCanvas->setDrawFilter(drawFilter)->unref();
420 }
421 }
422 }
423}
424
425bool DeferredDevice::isFreshFrame() {
426 bool ret = fFreshFrame;
427 fFreshFrame = false;
428 return ret;
429}
430
junov@chromium.org0a67f962012-09-19 22:48:34 +0000431void DeferredDevice::flushPendingCommands() {
junov@chromium.org88e29142012-08-07 16:48:22 +0000432 if (!fPipeController.hasRecorded()) {
433 return;
434 }
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000435 if (fNotificationClient) {
436 fNotificationClient->prepareForDraw();
junov@chromium.org88e29142012-08-07 16:48:22 +0000437 }
junov@chromium.org88e29142012-08-07 16:48:22 +0000438 fPipeWriter.flushRecording(true);
439 fPipeController.playback();
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000440 if (fNotificationClient) {
441 fNotificationClient->flushedDrawCommands();
442 }
443 fPreviousStorageAllocated = storageAllocatedForRecording();
junov@chromium.org88e29142012-08-07 16:48:22 +0000444}
445
446void DeferredDevice::flush() {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000447 this->flushPendingCommands();
junov@chromium.org88e29142012-08-07 16:48:22 +0000448 fImmediateCanvas->flush();
449}
450
451size_t DeferredDevice::freeMemoryIfPossible(size_t bytesToFree) {
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000452 size_t val = fPipeWriter.freeMemoryIfPossible(bytesToFree);
453 fPreviousStorageAllocated = storageAllocatedForRecording();
454 return val;
junov@chromium.org88e29142012-08-07 16:48:22 +0000455}
456
457size_t DeferredDevice::storageAllocatedForRecording() const {
458 return (fPipeController.storageAllocatedForRecording()
459 + fPipeWriter.storageAllocatedForRecording());
460}
461
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000462void DeferredDevice::recordedDrawCommand() {
junov@chromium.org88e29142012-08-07 16:48:22 +0000463 size_t storageAllocated = this->storageAllocatedForRecording();
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000464
junov@chromium.org88e29142012-08-07 16:48:22 +0000465 if (storageAllocated > fMaxRecordingStorageBytes) {
466 // First, attempt to reduce cache without flushing
467 size_t tryFree = storageAllocated - fMaxRecordingStorageBytes;
468 if (this->freeMemoryIfPossible(tryFree) < tryFree) {
469 // Flush is necessary to free more space.
junov@chromium.org0a67f962012-09-19 22:48:34 +0000470 this->flushPendingCommands();
junov@chromium.org88e29142012-08-07 16:48:22 +0000471 // Free as much as possible to avoid oscillating around fMaxRecordingStorageBytes
472 // which could cause a high flushing frequency.
bsalomon@google.com100abf42012-09-05 17:40:04 +0000473 this->freeMemoryIfPossible(~0U);
junov@chromium.org88e29142012-08-07 16:48:22 +0000474 }
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000475 storageAllocated = this->storageAllocatedForRecording();
junov@chromium.org88e29142012-08-07 16:48:22 +0000476 }
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000477
rmistry@google.comd6176b02012-08-23 18:14:13 +0000478 if (fNotificationClient &&
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000479 storageAllocated != fPreviousStorageAllocated) {
480 fPreviousStorageAllocated = storageAllocated;
481 fNotificationClient->storageAllocatedForRecordingChanged(storageAllocated);
482 }
483}
484
485SkCanvas* DeferredDevice::recordingCanvas() {
junov@chromium.org88e29142012-08-07 16:48:22 +0000486 return fRecordingCanvas;
487}
488
rmistry@google.comd6176b02012-08-23 18:14:13 +0000489uint32_t DeferredDevice::getDeviceCapabilities() {
junov@chromium.org88e29142012-08-07 16:48:22 +0000490 return fImmediateDevice->getDeviceCapabilities();
491}
492
rmistry@google.comd6176b02012-08-23 18:14:13 +0000493int DeferredDevice::width() const {
junov@chromium.org88e29142012-08-07 16:48:22 +0000494 return fImmediateDevice->width();
495}
496
497int DeferredDevice::height() const {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000498 return fImmediateDevice->height();
junov@chromium.org88e29142012-08-07 16:48:22 +0000499}
500
501SkGpuRenderTarget* DeferredDevice::accessRenderTarget() {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000502 this->flushPendingCommands();
junov@chromium.org88e29142012-08-07 16:48:22 +0000503 return fImmediateDevice->accessRenderTarget();
504}
505
506void DeferredDevice::writePixels(const SkBitmap& bitmap,
507 int x, int y, SkCanvas::Config8888 config8888) {
508
509 if (x <= 0 && y <= 0 && (x + bitmap.width()) >= width() &&
510 (y + bitmap.height()) >= height()) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000511 this->skipPendingCommands();
junov@chromium.org88e29142012-08-07 16:48:22 +0000512 }
513
514 if (SkBitmap::kARGB_8888_Config == bitmap.config() &&
515 SkCanvas::kNative_Premul_Config8888 != config8888 &&
516 kPMColorAlias != config8888) {
517 //Special case config: no deferral
junov@chromium.org0a67f962012-09-19 22:48:34 +0000518 this->flushPendingCommands();
junov@chromium.org88e29142012-08-07 16:48:22 +0000519 fImmediateDevice->writePixels(bitmap, x, y, config8888);
520 return;
521 }
522
523 SkPaint paint;
524 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
525 if (shouldDrawImmediately(&bitmap, NULL)) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000526 this->flushPendingCommands();
junov@chromium.org88e29142012-08-07 16:48:22 +0000527 fImmediateCanvas->drawSprite(bitmap, x, y, &paint);
528 } else {
529 this->recordingCanvas()->drawSprite(bitmap, x, y, &paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000530 this->recordedDrawCommand();
531
junov@chromium.org88e29142012-08-07 16:48:22 +0000532 }
533}
534
535const SkBitmap& DeferredDevice::onAccessBitmap(SkBitmap*) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000536 this->flushPendingCommands();
junov@chromium.org88e29142012-08-07 16:48:22 +0000537 return fImmediateDevice->accessBitmap(false);
538}
539
540SkDevice* DeferredDevice::onCreateCompatibleDevice(
541 SkBitmap::Config config, int width, int height, bool isOpaque,
542 Usage usage) {
543
544 // Save layer usage not supported, and not required by SkDeferredCanvas.
545 SkASSERT(usage != kSaveLayer_Usage);
546 // Create a compatible non-deferred device.
547 SkAutoTUnref<SkDevice> compatibleDevice
548 (fImmediateDevice->createCompatibleDevice(config, width, height,
549 isOpaque));
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000550 return SkNEW_ARGS(DeferredDevice, (compatibleDevice, fNotificationClient));
junov@chromium.org88e29142012-08-07 16:48:22 +0000551}
552
553bool DeferredDevice::onReadPixels(
554 const SkBitmap& bitmap, int x, int y, SkCanvas::Config8888 config8888) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000555 this->flushPendingCommands();
junov@chromium.org88e29142012-08-07 16:48:22 +0000556 return fImmediateCanvas->readPixels(const_cast<SkBitmap*>(&bitmap),
557 x, y, config8888);
558}
559
560
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000561SkDeferredCanvas::SkDeferredCanvas() {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000562 this->init();
junov@google.com4370aed2012-01-18 16:21:08 +0000563}
564
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000565SkDeferredCanvas::SkDeferredCanvas(SkDevice* device) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000566 this->init();
567 this->setDevice(device);
junov@google.com4370aed2012-01-18 16:21:08 +0000568}
569
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000570void SkDeferredCanvas::init() {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000571 fDeferredDrawing = true; // On by default
junov@google.com4370aed2012-01-18 16:21:08 +0000572}
573
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000574void SkDeferredCanvas::setMaxRecordingStorage(size_t maxStorage) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000575 this->validate();
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000576 this->getDeferredDevice()->setMaxRecordingStorage(maxStorage);
577}
578
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000579size_t SkDeferredCanvas::storageAllocatedForRecording() const {
580 return this->getDeferredDevice()->storageAllocatedForRecording();
581}
582
583size_t SkDeferredCanvas::freeMemoryIfPossible(size_t bytesToFree) {
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000584 return this->getDeferredDevice()->freeMemoryIfPossible(bytesToFree);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000585}
586
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000587void SkDeferredCanvas::recordedDrawCommand() {
588 if (fDeferredDrawing) {
589 this->getDeferredDevice()->recordedDrawCommand();
590 }
591}
592
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000593void SkDeferredCanvas::validate() const {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000594 SkASSERT(this->getDevice());
junov@google.com4370aed2012-01-18 16:21:08 +0000595}
596
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000597SkCanvas* SkDeferredCanvas::drawingCanvas() const {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000598 this->validate();
599 return fDeferredDrawing ? this->getDeferredDevice()->recordingCanvas() :
600 this->getDeferredDevice()->immediateCanvas();
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000601}
602
junov@chromium.org88e29142012-08-07 16:48:22 +0000603SkCanvas* SkDeferredCanvas::immediateCanvas() const {
604 this->validate();
605 return this->getDeferredDevice()->immediateCanvas();
606}
607
608DeferredDevice* SkDeferredCanvas::getDeferredDevice() const {
609 return static_cast<DeferredDevice*>(this->getDevice());
junov@google.com4370aed2012-01-18 16:21:08 +0000610}
611
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000612void SkDeferredCanvas::setDeferredDrawing(bool val) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000613 this->validate(); // Must set device before calling this method
junov@google.com4370aed2012-01-18 16:21:08 +0000614 if (val != fDeferredDrawing) {
615 if (fDeferredDrawing) {
junov@chromium.org5e5a0952012-02-28 15:27:59 +0000616 // Going live.
junov@chromium.org0a67f962012-09-19 22:48:34 +0000617 this->getDeferredDevice()->flushPendingCommands();
junov@google.com4370aed2012-01-18 16:21:08 +0000618 }
619 fDeferredDrawing = val;
620 }
621}
622
junov@chromium.org88e29142012-08-07 16:48:22 +0000623bool SkDeferredCanvas::isDeferredDrawing() const {
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +0000624 return fDeferredDrawing;
625}
626
junov@chromium.org88e29142012-08-07 16:48:22 +0000627bool SkDeferredCanvas::isFreshFrame() const {
628 return this->getDeferredDevice()->isFreshFrame();
629}
630
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000631SkDeferredCanvas::~SkDeferredCanvas() {
junov@google.com4370aed2012-01-18 16:21:08 +0000632}
633
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000634SkDevice* SkDeferredCanvas::setDevice(SkDevice* device) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000635 this->INHERITED::setDevice(SkNEW_ARGS(DeferredDevice, (device)))->unref();
junov@google.com4370aed2012-01-18 16:21:08 +0000636 return device;
637}
638
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000639SkDeferredCanvas::NotificationClient* SkDeferredCanvas::setNotificationClient(
640 NotificationClient* notificationClient) {
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000641
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000642 DeferredDevice* deferredDevice = this->getDeferredDevice();
junov@google.com4370aed2012-01-18 16:21:08 +0000643 SkASSERT(deferredDevice);
644 if (deferredDevice) {
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000645 deferredDevice->setNotificationClient(notificationClient);
junov@google.com4370aed2012-01-18 16:21:08 +0000646 }
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000647 return notificationClient;
junov@google.com4370aed2012-01-18 16:21:08 +0000648}
649
650bool SkDeferredCanvas::isFullFrame(const SkRect* rect,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000651 const SkPaint* paint) const {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000652 SkCanvas* canvas = this->drawingCanvas();
653 SkISize canvasSize = this->getDeviceSize();
junov@google.com4370aed2012-01-18 16:21:08 +0000654 if (rect) {
655 if (!canvas->getTotalMatrix().rectStaysRect()) {
656 return false; // conservative
657 }
658
659 SkRect transformedRect;
660 canvas->getTotalMatrix().mapRect(&transformedRect, *rect);
661
662 if (paint) {
663 SkPaint::Style paintStyle = paint->getStyle();
rmistry@google.comd6176b02012-08-23 18:14:13 +0000664 if (!(paintStyle == SkPaint::kFill_Style ||
junov@google.com4370aed2012-01-18 16:21:08 +0000665 paintStyle == SkPaint::kStrokeAndFill_Style)) {
666 return false;
667 }
668 if (paint->getMaskFilter() || paint->getLooper()
669 || paint->getPathEffect() || paint->getImageFilter()) {
670 return false; // conservative
671 }
672 }
673
674 // The following test holds with AA enabled, and is conservative
675 // by a 0.5 pixel margin with AA disabled
rmistry@google.comd6176b02012-08-23 18:14:13 +0000676 if (transformedRect.fLeft > SkIntToScalar(0) ||
677 transformedRect.fTop > SkIntToScalar(0) ||
junov@chromium.orgb1e218e2012-02-13 22:27:58 +0000678 transformedRect.fRight < SkIntToScalar(canvasSize.fWidth) ||
679 transformedRect.fBottom < SkIntToScalar(canvasSize.fHeight)) {
junov@google.com4370aed2012-01-18 16:21:08 +0000680 return false;
681 }
682 }
683
684 switch (canvas->getClipType()) {
685 case SkCanvas::kRect_ClipType :
686 {
687 SkIRect bounds;
688 canvas->getClipDeviceBounds(&bounds);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000689 if (bounds.fLeft > 0 || bounds.fTop > 0 ||
690 bounds.fRight < canvasSize.fWidth ||
junov@google.com4370aed2012-01-18 16:21:08 +0000691 bounds.fBottom < canvasSize.fHeight)
692 return false;
693 }
694 break;
695 case SkCanvas::kComplex_ClipType :
696 return false; // conservative
697 case SkCanvas::kEmpty_ClipType:
698 default:
699 break;
700 };
701
702 return true;
703}
704
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000705int SkDeferredCanvas::save(SaveFlags flags) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000706 this->drawingCanvas()->save(flags);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000707 int val = this->INHERITED::save(flags);
708 this->recordedDrawCommand();
709
710 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000711}
712
713int SkDeferredCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000714 SaveFlags flags) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000715 this->drawingCanvas()->saveLayer(bounds, paint, flags);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000716 int count = this->INHERITED::save(flags);
717 this->clipRectBounds(bounds, flags, NULL);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000718 this->recordedDrawCommand();
719
junov@chromium.orga907ac32012-02-24 21:54:07 +0000720 return count;
junov@google.com4370aed2012-01-18 16:21:08 +0000721}
722
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000723void SkDeferredCanvas::restore() {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000724 this->drawingCanvas()->restore();
junov@chromium.orga907ac32012-02-24 21:54:07 +0000725 this->INHERITED::restore();
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000726 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000727}
728
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000729bool SkDeferredCanvas::isDrawingToLayer() const {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000730 return this->drawingCanvas()->isDrawingToLayer();
junov@google.com4370aed2012-01-18 16:21:08 +0000731}
732
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000733bool SkDeferredCanvas::translate(SkScalar dx, SkScalar dy) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000734 this->drawingCanvas()->translate(dx, dy);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000735 bool val = this->INHERITED::translate(dx, dy);
736 this->recordedDrawCommand();
737 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000738}
739
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000740bool SkDeferredCanvas::scale(SkScalar sx, SkScalar sy) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000741 this->drawingCanvas()->scale(sx, sy);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000742 bool val = this->INHERITED::scale(sx, sy);
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::rotate(SkScalar degrees) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000748 this->drawingCanvas()->rotate(degrees);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000749 bool val = this->INHERITED::rotate(degrees);
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::skew(SkScalar sx, SkScalar sy) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000755 this->drawingCanvas()->skew(sx, sy);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000756 bool val = this->INHERITED::skew(sx, sy);
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::concat(const SkMatrix& matrix) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000762 this->drawingCanvas()->concat(matrix);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000763 bool val = this->INHERITED::concat(matrix);
764 this->recordedDrawCommand();
765 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000766}
767
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000768void SkDeferredCanvas::setMatrix(const SkMatrix& matrix) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000769 this->drawingCanvas()->setMatrix(matrix);
junov@chromium.orga907ac32012-02-24 21:54:07 +0000770 this->INHERITED::setMatrix(matrix);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000771 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000772}
773
774bool SkDeferredCanvas::clipRect(const SkRect& rect,
775 SkRegion::Op op,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000776 bool doAntiAlias) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000777 this->drawingCanvas()->clipRect(rect, op, doAntiAlias);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000778 bool val = this->INHERITED::clipRect(rect, op, doAntiAlias);
779 this->recordedDrawCommand();
780 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000781}
782
783bool SkDeferredCanvas::clipPath(const SkPath& path,
784 SkRegion::Op op,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000785 bool doAntiAlias) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000786 this->drawingCanvas()->clipPath(path, op, doAntiAlias);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000787 bool val = this->INHERITED::clipPath(path, op, doAntiAlias);
788 this->recordedDrawCommand();
789 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000790}
791
792bool SkDeferredCanvas::clipRegion(const SkRegion& deviceRgn,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000793 SkRegion::Op op) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000794 this->drawingCanvas()->clipRegion(deviceRgn, op);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000795 bool val = this->INHERITED::clipRegion(deviceRgn, op);
796 this->recordedDrawCommand();
797 return val;
junov@google.com4370aed2012-01-18 16:21:08 +0000798}
799
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000800void SkDeferredCanvas::clear(SkColor color) {
junov@google.com4370aed2012-01-18 16:21:08 +0000801 // purge pending commands
802 if (fDeferredDrawing) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000803 this->getDeferredDevice()->skipPendingCommands();
junov@google.com4370aed2012-01-18 16:21:08 +0000804 }
805
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000806 this->drawingCanvas()->clear(color);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000807 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000808}
809
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000810void SkDeferredCanvas::drawPaint(const SkPaint& paint) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000811 if (fDeferredDrawing && this->isFullFrame(NULL, &paint) &&
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000812 isPaintOpaque(&paint)) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000813 this->getDeferredDevice()->skipPendingCommands();
junov@google.com4370aed2012-01-18 16:21:08 +0000814 }
junov@chromium.org10f7f972012-07-31 21:01:51 +0000815 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000816 this->drawingCanvas()->drawPaint(paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000817 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000818}
819
820void SkDeferredCanvas::drawPoints(PointMode mode, size_t count,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000821 const SkPoint pts[], const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000822 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000823 this->drawingCanvas()->drawPoints(mode, count, pts, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000824 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000825}
826
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000827void SkDeferredCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000828 if (fDeferredDrawing && this->isFullFrame(&rect, &paint) &&
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000829 isPaintOpaque(&paint)) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000830 this->getDeferredDevice()->skipPendingCommands();
junov@google.com4370aed2012-01-18 16:21:08 +0000831 }
832
junov@chromium.org10f7f972012-07-31 21:01:51 +0000833 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000834 this->drawingCanvas()->drawRect(rect, 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::drawPath(const SkPath& path, const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000839 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000840 this->drawingCanvas()->drawPath(path, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000841 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000842}
843
844void SkDeferredCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000845 SkScalar top, const SkPaint* paint) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000846 SkRect bitmapRect = SkRect::MakeXYWH(left, top,
847 SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
rmistry@google.comd6176b02012-08-23 18:14:13 +0000848 if (fDeferredDrawing &&
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000849 this->isFullFrame(&bitmapRect, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000850 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000851 this->getDeferredDevice()->skipPendingCommands();
junov@google.com4370aed2012-01-18 16:21:08 +0000852 }
853
junov@chromium.org10f7f972012-07-31 21:01:51 +0000854 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000855 this->drawingCanvas()->drawBitmap(bitmap, left, top, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000856 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000857}
858
reed@google.com71121732012-09-18 15:14:33 +0000859void SkDeferredCanvas::drawBitmapRectToRect(const SkBitmap& bitmap,
860 const SkRect* src,
861 const SkRect& dst,
862 const SkPaint* paint) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000863 if (fDeferredDrawing &&
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000864 this->isFullFrame(&dst, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000865 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000866 this->getDeferredDevice()->skipPendingCommands();
junov@google.com4370aed2012-01-18 16:21:08 +0000867 }
868
junov@chromium.org10f7f972012-07-31 21:01:51 +0000869 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
reed@google.com71121732012-09-18 15:14:33 +0000870 this->drawingCanvas()->drawBitmapRectToRect(bitmap, src, dst, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000871 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000872}
873
874
875void SkDeferredCanvas::drawBitmapMatrix(const SkBitmap& bitmap,
876 const SkMatrix& m,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000877 const SkPaint* paint) {
junov@google.com4370aed2012-01-18 16:21:08 +0000878 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
879 // covers canvas entirely and transformed bitmap covers canvas entirely
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()->drawBitmapMatrix(bitmap, m, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000882 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000883}
884
885void SkDeferredCanvas::drawBitmapNine(const SkBitmap& bitmap,
886 const SkIRect& center, const SkRect& dst,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000887 const SkPaint* paint) {
junov@google.com4370aed2012-01-18 16:21:08 +0000888 // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
889 // covers canvas entirely and dst covers canvas entirely
junov@chromium.org10f7f972012-07-31 21:01:51 +0000890 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000891 this->drawingCanvas()->drawBitmapNine(bitmap, center, dst, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000892 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000893}
894
895void SkDeferredCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000896 const SkPaint* paint) {
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000897 SkRect bitmapRect = SkRect::MakeXYWH(
898 SkIntToScalar(left),
rmistry@google.comd6176b02012-08-23 18:14:13 +0000899 SkIntToScalar(top),
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000900 SkIntToScalar(bitmap.width()),
901 SkIntToScalar(bitmap.height()));
rmistry@google.comd6176b02012-08-23 18:14:13 +0000902 if (fDeferredDrawing &&
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000903 this->isFullFrame(&bitmapRect, paint) &&
junov@chromium.org87f982c2012-02-23 21:34:34 +0000904 isPaintOpaque(paint, &bitmap)) {
junov@chromium.org0a67f962012-09-19 22:48:34 +0000905 this->getDeferredDevice()->skipPendingCommands();
junov@google.com4370aed2012-01-18 16:21:08 +0000906 }
907
junov@chromium.org10f7f972012-07-31 21:01:51 +0000908 AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000909 this->drawingCanvas()->drawSprite(bitmap, left, top, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000910 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000911}
912
913void SkDeferredCanvas::drawText(const void* text, size_t byteLength,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000914 SkScalar x, SkScalar y, const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000915 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000916 this->drawingCanvas()->drawText(text, byteLength, x, y, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000917 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000918}
919
920void SkDeferredCanvas::drawPosText(const void* text, size_t byteLength,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000921 const SkPoint pos[], 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()->drawPosText(text, byteLength, pos, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000924 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000925}
926
927void SkDeferredCanvas::drawPosTextH(const void* text, size_t byteLength,
928 const SkScalar xpos[], SkScalar constY,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000929 const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000930 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000931 this->drawingCanvas()->drawPosTextH(text, byteLength, xpos, constY, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000932 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000933}
934
935void SkDeferredCanvas::drawTextOnPath(const void* text, size_t byteLength,
936 const SkPath& path,
937 const SkMatrix* matrix,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000938 const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000939 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000940 this->drawingCanvas()->drawTextOnPath(text, byteLength, path, matrix, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000941 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000942}
943
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000944void SkDeferredCanvas::drawPicture(SkPicture& picture) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000945 this->drawingCanvas()->drawPicture(picture);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000946 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000947}
948
949void SkDeferredCanvas::drawVertices(VertexMode vmode, int vertexCount,
950 const SkPoint vertices[],
951 const SkPoint texs[],
952 const SkColor colors[], SkXfermode* xmode,
953 const uint16_t indices[], int indexCount,
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000954 const SkPaint& paint) {
junov@chromium.org10f7f972012-07-31 21:01:51 +0000955 AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000956 this->drawingCanvas()->drawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
957 indices, indexCount, paint);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000958 this->recordedDrawCommand();
junov@google.com4370aed2012-01-18 16:21:08 +0000959}
960
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000961SkBounder* SkDeferredCanvas::setBounder(SkBounder* bounder) {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000962 this->drawingCanvas()->setBounder(bounder);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000963 this->INHERITED::setBounder(bounder);
964 this->recordedDrawCommand();
965 return bounder;
junov@google.com4370aed2012-01-18 16:21:08 +0000966}
967
junov@chromium.orgc16ca922012-02-24 22:06:27 +0000968SkDrawFilter* SkDeferredCanvas::setDrawFilter(SkDrawFilter* filter) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000969 this->drawingCanvas()->setDrawFilter(filter);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000970 this->INHERITED::setDrawFilter(filter);
971 this->recordedDrawCommand();
rmistry@google.comd6176b02012-08-23 18:14:13 +0000972 return filter;
junov@google.com4370aed2012-01-18 16:21:08 +0000973}
974
975SkCanvas* SkDeferredCanvas::canvasForDrawIter() {
junov@chromium.org9060c9b2012-08-07 15:14:01 +0000976 return this->drawingCanvas();
junov@google.com4370aed2012-01-18 16:21:08 +0000977}