SkDeferredCanvas.cpp revision 0a67f964b3ed6046303655ced757be7c0f2c060c
1
2/*
3 * Copyright 2012 Google Inc.
4 *
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
11#include "SkChunkAlloc.h"
12#include "SkColorFilter.h"
13#include "SkDevice.h"
14#include "SkDrawFilter.h"
15#include "SkGPipe.h"
16#include "SkPaint.h"
17#include "SkShader.h"
18
19enum {
20    // Deferred canvas will auto-flush when recording reaches this limit
21    kDefaultMaxRecordingStorageBytes = 64*1024*1024,
22};
23
24namespace {
25bool 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;
38            if (shader->asABitmap(&bm, NULL, NULL) &&
39                NULL != bm.getTexture()) {
40                return true;
41            }
42        }
43    }
44    return false;
45}
46}
47
48class AutoImmediateDrawIfNeeded {
49public:
50    AutoImmediateDrawIfNeeded(SkDeferredCanvas& canvas, const SkBitmap* bitmap,
51                              const SkPaint* paint) {
52        this->init(canvas, bitmap, paint);
53    }
54
55    AutoImmediateDrawIfNeeded(SkDeferredCanvas& canvas, const SkPaint* paint) {
56        this->init(canvas, NULL, paint);
57    }
58
59    ~AutoImmediateDrawIfNeeded() {
60        if (fCanvas) {
61            fCanvas->setDeferredDrawing(true);
62        }
63    }
64private:
65    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
75    SkDeferredCanvas* fCanvas;
76};
77
78namespace {
79
80bool isPaintOpaque(const SkPaint* paint,
81                   const SkBitmap* bmpReplacesShader = NULL) {
82    // TODO: SkXfermode should have a virtual isOpaque method, which would
83    // make it possible to test modes that do not have a Coeff representation.
84
85    if (!paint) {
86        return bmpReplacesShader ? bmpReplacesShader->isOpaque() : true;
87    }
88
89    SkXfermode::Coeff srcCoeff, dstCoeff;
90    if (SkXfermode::AsCoeff(paint->getXfermode(), &srcCoeff, &dstCoeff)){
91        switch (dstCoeff) {
92        case SkXfermode::kZero_Coeff:
93            return true;
94        case SkXfermode::kISA_Coeff:
95            if (paint->getAlpha() != 255) {
96                break;
97            }
98            if (bmpReplacesShader) {
99                if (!bmpReplacesShader->isOpaque()) {
100                    break;
101                }
102            } else if (paint->getShader() && !paint->getShader()->isOpaque()) {
103                break;
104            }
105            if (paint->getColorFilter() &&
106                ((paint->getColorFilter()->getFlags() &
107                SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
108                break;
109            }
110            return true;
111        case SkXfermode::kSA_Coeff:
112            if (paint->getAlpha() != 0) {
113                break;
114            }
115            if (paint->getColorFilter() &&
116                ((paint->getColorFilter()->getFlags() &
117                SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
118                break;
119            }
120            return true;
121        case SkXfermode::kSC_Coeff:
122            if (paint->getColor() != 0) { // all components must be 0
123                break;
124            }
125            if (bmpReplacesShader || paint->getShader()) {
126                break;
127            }
128            if (paint->getColorFilter() && (
129                (paint->getColorFilter()->getFlags() &
130                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
143//-----------------------------------------------------------------------------
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() {
206
207    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,
234        SkDeferredCanvas::NotificationClient* notificationClient = NULL);
235    ~DeferredDevice();
236
237    void setNotificationClient(SkDeferredCanvas::NotificationClient* notificationClient);
238    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);
244    void flushPendingCommands();
245    void skipPendingCommands();
246    void setMaxRecordingStorage(size_t);
247    void recordedDrawCommand();
248
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;
339    SkDeferredCanvas::NotificationClient* fNotificationClient;
340    bool fFreshFrame;
341    size_t fMaxRecordingStorageBytes;
342    size_t fPreviousStorageAllocated;
343};
344
345DeferredDevice::DeferredDevice(
346    SkDevice* immediateDevice, SkDeferredCanvas::NotificationClient* notificationClient) :
347    SkDevice(SkBitmap::kNo_Config, immediateDevice->width(),
348             immediateDevice->height(), immediateDevice->isOpaque())
349    , fRecordingCanvas(NULL)
350    , fFreshFrame(true)
351    , fPreviousStorageAllocated(0){
352
353    fMaxRecordingStorageBytes = kDefaultMaxRecordingStorageBytes;
354    fNotificationClient = notificationClient;
355    fImmediateDevice = immediateDevice; // ref counted via fImmediateCanvas
356    fImmediateCanvas = SkNEW_ARGS(SkCanvas, (fImmediateDevice));
357    fPipeController.setPlaybackCanvas(fImmediateCanvas);
358    this->beginRecording();
359}
360
361DeferredDevice::~DeferredDevice() {
362    this->flushPendingCommands();
363    SkSafeUnref(fImmediateCanvas);
364}
365
366void DeferredDevice::setMaxRecordingStorage(size_t maxStorage) {
367    fMaxRecordingStorageBytes = maxStorage;
368    this->recordingCanvas(); // Accessing the recording canvas applies the new limit.
369}
370
371void DeferredDevice::endRecording() {
372    fPipeWriter.endRecording();
373    fPipeController.reset();
374    fRecordingCanvas = NULL;
375}
376
377void DeferredDevice::beginRecording() {
378    SkASSERT(NULL == fRecordingCanvas);
379    fRecordingCanvas = fPipeWriter.startRecording(&fPipeController, 0,
380        fImmediateDevice->width(), fImmediateDevice->height());
381}
382
383void DeferredDevice::setNotificationClient(
384    SkDeferredCanvas::NotificationClient* notificationClient) {
385    fNotificationClient = notificationClient;
386}
387
388void DeferredDevice::skipPendingCommands() {
389    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
394        // with an empty stack.  A save count of 1 means an empty stack.
395        SkASSERT(fRecordingCanvas->getSaveCount() >= 1);
396        if (fRecordingCanvas->getSaveCount() == 1) {
397
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();
408            fPreviousStorageAllocated = storageAllocatedForRecording();
409
410            // Restore pre-purge state
411            if (!clipRegion.isEmpty()) {
412                fRecordingCanvas->clipRegion(clipRegion,
413                    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
431void DeferredDevice::flushPendingCommands() {
432    if (!fPipeController.hasRecorded()) {
433        return;
434    }
435    if (fNotificationClient) {
436        fNotificationClient->prepareForDraw();
437    }
438    fPipeWriter.flushRecording(true);
439    fPipeController.playback();
440    if (fNotificationClient) {
441        fNotificationClient->flushedDrawCommands();
442    }
443    fPreviousStorageAllocated = storageAllocatedForRecording();
444}
445
446void DeferredDevice::flush() {
447    this->flushPendingCommands();
448    fImmediateCanvas->flush();
449}
450
451size_t DeferredDevice::freeMemoryIfPossible(size_t bytesToFree) {
452    size_t val = fPipeWriter.freeMemoryIfPossible(bytesToFree);
453    fPreviousStorageAllocated = storageAllocatedForRecording();
454    return val;
455}
456
457size_t DeferredDevice::storageAllocatedForRecording() const {
458    return (fPipeController.storageAllocatedForRecording()
459            + fPipeWriter.storageAllocatedForRecording());
460}
461
462void DeferredDevice::recordedDrawCommand() {
463    size_t storageAllocated = this->storageAllocatedForRecording();
464
465    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.
470            this->flushPendingCommands();
471            // Free as much as possible to avoid oscillating around fMaxRecordingStorageBytes
472            // which could cause a high flushing frequency.
473            this->freeMemoryIfPossible(~0U);
474        }
475        storageAllocated = this->storageAllocatedForRecording();
476    }
477
478    if (fNotificationClient &&
479        storageAllocated != fPreviousStorageAllocated) {
480        fPreviousStorageAllocated = storageAllocated;
481        fNotificationClient->storageAllocatedForRecordingChanged(storageAllocated);
482    }
483}
484
485SkCanvas* DeferredDevice::recordingCanvas() {
486    return fRecordingCanvas;
487}
488
489uint32_t DeferredDevice::getDeviceCapabilities() {
490    return fImmediateDevice->getDeviceCapabilities();
491}
492
493int DeferredDevice::width() const {
494    return fImmediateDevice->width();
495}
496
497int DeferredDevice::height() const {
498    return fImmediateDevice->height();
499}
500
501SkGpuRenderTarget* DeferredDevice::accessRenderTarget() {
502    this->flushPendingCommands();
503    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()) {
511        this->skipPendingCommands();
512    }
513
514    if (SkBitmap::kARGB_8888_Config == bitmap.config() &&
515        SkCanvas::kNative_Premul_Config8888 != config8888 &&
516        kPMColorAlias != config8888) {
517        //Special case config: no deferral
518        this->flushPendingCommands();
519        fImmediateDevice->writePixels(bitmap, x, y, config8888);
520        return;
521    }
522
523    SkPaint paint;
524    paint.setXfermodeMode(SkXfermode::kSrc_Mode);
525    if (shouldDrawImmediately(&bitmap, NULL)) {
526        this->flushPendingCommands();
527        fImmediateCanvas->drawSprite(bitmap, x, y, &paint);
528    } else {
529        this->recordingCanvas()->drawSprite(bitmap, x, y, &paint);
530        this->recordedDrawCommand();
531
532    }
533}
534
535const SkBitmap& DeferredDevice::onAccessBitmap(SkBitmap*) {
536    this->flushPendingCommands();
537    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));
550    return SkNEW_ARGS(DeferredDevice, (compatibleDevice, fNotificationClient));
551}
552
553bool DeferredDevice::onReadPixels(
554    const SkBitmap& bitmap, int x, int y, SkCanvas::Config8888 config8888) {
555    this->flushPendingCommands();
556    return fImmediateCanvas->readPixels(const_cast<SkBitmap*>(&bitmap),
557                                                   x, y, config8888);
558}
559
560
561SkDeferredCanvas::SkDeferredCanvas() {
562    this->init();
563}
564
565SkDeferredCanvas::SkDeferredCanvas(SkDevice* device) {
566    this->init();
567    this->setDevice(device);
568}
569
570void SkDeferredCanvas::init() {
571    fDeferredDrawing = true; // On by default
572}
573
574void SkDeferredCanvas::setMaxRecordingStorage(size_t maxStorage) {
575    this->validate();
576    this->getDeferredDevice()->setMaxRecordingStorage(maxStorage);
577}
578
579size_t SkDeferredCanvas::storageAllocatedForRecording() const {
580    return this->getDeferredDevice()->storageAllocatedForRecording();
581}
582
583size_t SkDeferredCanvas::freeMemoryIfPossible(size_t bytesToFree) {
584    return this->getDeferredDevice()->freeMemoryIfPossible(bytesToFree);
585}
586
587void SkDeferredCanvas::recordedDrawCommand() {
588    if (fDeferredDrawing) {
589        this->getDeferredDevice()->recordedDrawCommand();
590    }
591}
592
593void SkDeferredCanvas::validate() const {
594    SkASSERT(this->getDevice());
595}
596
597SkCanvas* SkDeferredCanvas::drawingCanvas() const {
598    this->validate();
599    return fDeferredDrawing ? this->getDeferredDevice()->recordingCanvas() :
600        this->getDeferredDevice()->immediateCanvas();
601}
602
603SkCanvas* SkDeferredCanvas::immediateCanvas() const {
604    this->validate();
605    return this->getDeferredDevice()->immediateCanvas();
606}
607
608DeferredDevice* SkDeferredCanvas::getDeferredDevice() const {
609    return static_cast<DeferredDevice*>(this->getDevice());
610}
611
612void SkDeferredCanvas::setDeferredDrawing(bool val) {
613    this->validate(); // Must set device before calling this method
614    if (val != fDeferredDrawing) {
615        if (fDeferredDrawing) {
616            // Going live.
617            this->getDeferredDevice()->flushPendingCommands();
618        }
619        fDeferredDrawing = val;
620    }
621}
622
623bool SkDeferredCanvas::isDeferredDrawing() const {
624    return fDeferredDrawing;
625}
626
627bool SkDeferredCanvas::isFreshFrame() const {
628    return this->getDeferredDevice()->isFreshFrame();
629}
630
631SkDeferredCanvas::~SkDeferredCanvas() {
632}
633
634SkDevice* SkDeferredCanvas::setDevice(SkDevice* device) {
635    this->INHERITED::setDevice(SkNEW_ARGS(DeferredDevice, (device)))->unref();
636    return device;
637}
638
639SkDeferredCanvas::NotificationClient* SkDeferredCanvas::setNotificationClient(
640    NotificationClient* notificationClient) {
641
642    DeferredDevice* deferredDevice = this->getDeferredDevice();
643    SkASSERT(deferredDevice);
644    if (deferredDevice) {
645        deferredDevice->setNotificationClient(notificationClient);
646    }
647    return notificationClient;
648}
649
650bool SkDeferredCanvas::isFullFrame(const SkRect* rect,
651                                   const SkPaint* paint) const {
652    SkCanvas* canvas = this->drawingCanvas();
653    SkISize canvasSize = this->getDeviceSize();
654    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();
664            if (!(paintStyle == SkPaint::kFill_Style ||
665                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
676        if (transformedRect.fLeft > SkIntToScalar(0) ||
677            transformedRect.fTop > SkIntToScalar(0) ||
678            transformedRect.fRight < SkIntToScalar(canvasSize.fWidth) ||
679            transformedRect.fBottom < SkIntToScalar(canvasSize.fHeight)) {
680            return false;
681        }
682    }
683
684    switch (canvas->getClipType()) {
685        case SkCanvas::kRect_ClipType :
686            {
687                SkIRect bounds;
688                canvas->getClipDeviceBounds(&bounds);
689                if (bounds.fLeft > 0 || bounds.fTop > 0 ||
690                    bounds.fRight < canvasSize.fWidth ||
691                    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
705int SkDeferredCanvas::save(SaveFlags flags) {
706    this->drawingCanvas()->save(flags);
707    int val = this->INHERITED::save(flags);
708    this->recordedDrawCommand();
709
710    return val;
711}
712
713int SkDeferredCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
714                                SaveFlags flags) {
715    this->drawingCanvas()->saveLayer(bounds, paint, flags);
716    int count = this->INHERITED::save(flags);
717    this->clipRectBounds(bounds, flags, NULL);
718    this->recordedDrawCommand();
719
720    return count;
721}
722
723void SkDeferredCanvas::restore() {
724    this->drawingCanvas()->restore();
725    this->INHERITED::restore();
726    this->recordedDrawCommand();
727}
728
729bool SkDeferredCanvas::isDrawingToLayer() const {
730    return this->drawingCanvas()->isDrawingToLayer();
731}
732
733bool SkDeferredCanvas::translate(SkScalar dx, SkScalar dy) {
734    this->drawingCanvas()->translate(dx, dy);
735    bool val = this->INHERITED::translate(dx, dy);
736    this->recordedDrawCommand();
737    return val;
738}
739
740bool SkDeferredCanvas::scale(SkScalar sx, SkScalar sy) {
741    this->drawingCanvas()->scale(sx, sy);
742    bool val = this->INHERITED::scale(sx, sy);
743    this->recordedDrawCommand();
744    return val;
745}
746
747bool SkDeferredCanvas::rotate(SkScalar degrees) {
748    this->drawingCanvas()->rotate(degrees);
749    bool val = this->INHERITED::rotate(degrees);
750    this->recordedDrawCommand();
751    return val;
752}
753
754bool SkDeferredCanvas::skew(SkScalar sx, SkScalar sy) {
755    this->drawingCanvas()->skew(sx, sy);
756    bool val = this->INHERITED::skew(sx, sy);
757    this->recordedDrawCommand();
758    return val;
759}
760
761bool SkDeferredCanvas::concat(const SkMatrix& matrix) {
762    this->drawingCanvas()->concat(matrix);
763    bool val = this->INHERITED::concat(matrix);
764    this->recordedDrawCommand();
765    return val;
766}
767
768void SkDeferredCanvas::setMatrix(const SkMatrix& matrix) {
769    this->drawingCanvas()->setMatrix(matrix);
770    this->INHERITED::setMatrix(matrix);
771    this->recordedDrawCommand();
772}
773
774bool SkDeferredCanvas::clipRect(const SkRect& rect,
775                                SkRegion::Op op,
776                                bool doAntiAlias) {
777    this->drawingCanvas()->clipRect(rect, op, doAntiAlias);
778    bool val = this->INHERITED::clipRect(rect, op, doAntiAlias);
779    this->recordedDrawCommand();
780    return val;
781}
782
783bool SkDeferredCanvas::clipPath(const SkPath& path,
784                                SkRegion::Op op,
785                                bool doAntiAlias) {
786    this->drawingCanvas()->clipPath(path, op, doAntiAlias);
787    bool val = this->INHERITED::clipPath(path, op, doAntiAlias);
788    this->recordedDrawCommand();
789    return val;
790}
791
792bool SkDeferredCanvas::clipRegion(const SkRegion& deviceRgn,
793                                  SkRegion::Op op) {
794    this->drawingCanvas()->clipRegion(deviceRgn, op);
795    bool val = this->INHERITED::clipRegion(deviceRgn, op);
796    this->recordedDrawCommand();
797    return val;
798}
799
800void SkDeferredCanvas::clear(SkColor color) {
801    // purge pending commands
802    if (fDeferredDrawing) {
803        this->getDeferredDevice()->skipPendingCommands();
804    }
805
806    this->drawingCanvas()->clear(color);
807    this->recordedDrawCommand();
808}
809
810void SkDeferredCanvas::drawPaint(const SkPaint& paint) {
811    if (fDeferredDrawing && this->isFullFrame(NULL, &paint) &&
812        isPaintOpaque(&paint)) {
813        this->getDeferredDevice()->skipPendingCommands();
814    }
815    AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
816    this->drawingCanvas()->drawPaint(paint);
817    this->recordedDrawCommand();
818}
819
820void SkDeferredCanvas::drawPoints(PointMode mode, size_t count,
821                                  const SkPoint pts[], const SkPaint& paint) {
822    AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
823    this->drawingCanvas()->drawPoints(mode, count, pts, paint);
824    this->recordedDrawCommand();
825}
826
827void SkDeferredCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
828    if (fDeferredDrawing && this->isFullFrame(&rect, &paint) &&
829        isPaintOpaque(&paint)) {
830        this->getDeferredDevice()->skipPendingCommands();
831    }
832
833    AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
834    this->drawingCanvas()->drawRect(rect, paint);
835    this->recordedDrawCommand();
836}
837
838void SkDeferredCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
839    AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
840    this->drawingCanvas()->drawPath(path, paint);
841    this->recordedDrawCommand();
842}
843
844void SkDeferredCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left,
845                                  SkScalar top, const SkPaint* paint) {
846    SkRect bitmapRect = SkRect::MakeXYWH(left, top,
847        SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
848    if (fDeferredDrawing &&
849        this->isFullFrame(&bitmapRect, paint) &&
850        isPaintOpaque(paint, &bitmap)) {
851        this->getDeferredDevice()->skipPendingCommands();
852    }
853
854    AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
855    this->drawingCanvas()->drawBitmap(bitmap, left, top, paint);
856    this->recordedDrawCommand();
857}
858
859void SkDeferredCanvas::drawBitmapRectToRect(const SkBitmap& bitmap,
860                                            const SkRect* src,
861                                            const SkRect& dst,
862                                            const SkPaint* paint) {
863    if (fDeferredDrawing &&
864        this->isFullFrame(&dst, paint) &&
865        isPaintOpaque(paint, &bitmap)) {
866        this->getDeferredDevice()->skipPendingCommands();
867    }
868
869    AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
870    this->drawingCanvas()->drawBitmapRectToRect(bitmap, src, dst, paint);
871    this->recordedDrawCommand();
872}
873
874
875void SkDeferredCanvas::drawBitmapMatrix(const SkBitmap& bitmap,
876                                        const SkMatrix& m,
877                                        const SkPaint* paint) {
878    // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
879    // covers canvas entirely and transformed bitmap covers canvas entirely
880    AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
881    this->drawingCanvas()->drawBitmapMatrix(bitmap, m, paint);
882    this->recordedDrawCommand();
883}
884
885void SkDeferredCanvas::drawBitmapNine(const SkBitmap& bitmap,
886                                      const SkIRect& center, const SkRect& dst,
887                                      const SkPaint* paint) {
888    // TODO: reset recording canvas if paint+bitmap is opaque and clip rect
889    // covers canvas entirely and dst covers canvas entirely
890    AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
891    this->drawingCanvas()->drawBitmapNine(bitmap, center, dst, paint);
892    this->recordedDrawCommand();
893}
894
895void SkDeferredCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
896                                  const SkPaint* paint) {
897    SkRect bitmapRect = SkRect::MakeXYWH(
898        SkIntToScalar(left),
899        SkIntToScalar(top),
900        SkIntToScalar(bitmap.width()),
901        SkIntToScalar(bitmap.height()));
902    if (fDeferredDrawing &&
903        this->isFullFrame(&bitmapRect, paint) &&
904        isPaintOpaque(paint, &bitmap)) {
905        this->getDeferredDevice()->skipPendingCommands();
906    }
907
908    AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
909    this->drawingCanvas()->drawSprite(bitmap, left, top, paint);
910    this->recordedDrawCommand();
911}
912
913void SkDeferredCanvas::drawText(const void* text, size_t byteLength,
914                                SkScalar x, SkScalar y, const SkPaint& paint) {
915    AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
916    this->drawingCanvas()->drawText(text, byteLength, x, y, paint);
917    this->recordedDrawCommand();
918}
919
920void SkDeferredCanvas::drawPosText(const void* text, size_t byteLength,
921                                   const SkPoint pos[], const SkPaint& paint) {
922    AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
923    this->drawingCanvas()->drawPosText(text, byteLength, pos, paint);
924    this->recordedDrawCommand();
925}
926
927void SkDeferredCanvas::drawPosTextH(const void* text, size_t byteLength,
928                                    const SkScalar xpos[], SkScalar constY,
929                                    const SkPaint& paint) {
930    AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
931    this->drawingCanvas()->drawPosTextH(text, byteLength, xpos, constY, paint);
932    this->recordedDrawCommand();
933}
934
935void SkDeferredCanvas::drawTextOnPath(const void* text, size_t byteLength,
936                                      const SkPath& path,
937                                      const SkMatrix* matrix,
938                                      const SkPaint& paint) {
939    AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
940    this->drawingCanvas()->drawTextOnPath(text, byteLength, path, matrix, paint);
941    this->recordedDrawCommand();
942}
943
944void SkDeferredCanvas::drawPicture(SkPicture& picture) {
945    this->drawingCanvas()->drawPicture(picture);
946    this->recordedDrawCommand();
947}
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,
954                                    const SkPaint& paint) {
955    AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
956    this->drawingCanvas()->drawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
957                                        indices, indexCount, paint);
958    this->recordedDrawCommand();
959}
960
961SkBounder* SkDeferredCanvas::setBounder(SkBounder* bounder) {
962    this->drawingCanvas()->setBounder(bounder);
963    this->INHERITED::setBounder(bounder);
964    this->recordedDrawCommand();
965    return bounder;
966}
967
968SkDrawFilter* SkDeferredCanvas::setDrawFilter(SkDrawFilter* filter) {
969    this->drawingCanvas()->setDrawFilter(filter);
970    this->INHERITED::setDrawFilter(filter);
971    this->recordedDrawCommand();
972    return filter;
973}
974
975SkCanvas* SkDeferredCanvas::canvasForDrawIter() {
976    return this->drawingCanvas();
977}
978